diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 4a853a5f6..cc0d16b8f 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -1,8 +1,9 @@ -name: Build AppImage +name: AppImage Build on: push: branches: - dev + - releases tags: - '[0-9]+.*' pull_request: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..b90d30e27 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,89 @@ +name: "CodeQL" + +on: + push: + branches: [ 'dev' ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ 'dev' ] + schedule: + - cron: '56 5 * * 1' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + build_type: [release] + language: [ 'cpp', 'python' ] + + steps: + - name: Checkout source + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Install dependencies + run: | + echo "Running apt update." + sudo apt update + echo "Installing dependencies with apt." + DEBIAN_FRONTEND=noninteractive sudo apt install -y cmake libgtk-3-dev libgtkmm-3.0-dev liblensfun-dev librsvg2-dev liblcms2-dev libfftw3-dev libiptcdata0-dev libtiff5-dev libcanberra-gtk3-dev liblensfun-bin + + - name: Configure build + run: | + export REF_NAME_FILTERED="$(echo '${{github.ref_name}}' | sed 's/[^A-z0-9_.-]//g')" + echo "Setting cache suffix." + if [ '${{github.ref_type}}' == 'tag' ]; then + export CACHE_SUFFIX="" + else + export CACHE_SUFFIX="5-$REF_NAME_FILTERED" + fi + export CACHE_SUFFIX="$CACHE_SUFFIX-AppImage" + echo "Cache suffix is '$CACHE_SUFFIX'." + echo "Making build directory." + mkdir build + echo "Changing working directory to the build directory." + cd build + echo "Running CMake configure." + cmake \ + -DCMAKE_BUILD_TYPE='${{matrix.build_type}}' \ + -DCACHE_NAME_SUFFIX="$CACHE_SUFFIX" \ + -DPROC_TARGET_NUMBER="1" \ + -DBUILD_BUNDLE="ON" \ + -DBUNDLE_BASE_INSTALL_DIR="/" \ + -DOPTION_OMP="ON" \ + -DWITH_LTO="OFF" \ + -DWITH_PROF="OFF" \ + -DWITH_SAN="OFF" \ + -DWITH_SYSTEM_KLT="OFF" \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DLENSFUNDBDIR="../share/lensfun/version_1" \ + .. + echo "Recording filtered ref name." + echo "REF_NAME_FILTERED=$REF_NAME_FILTERED" >> $GITHUB_ENV + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Build RawTherapee + working-directory: ./build + run: | + echo "Running make install." + make -j$(nproc) install DESTDIR=AppDir/usr/bin + echo "Moving usr/bin/share to usr/share." + mv AppDir/usr/bin/share AppDir/usr/ + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/main.yml b/.github/workflows/macos.yml similarity index 79% rename from .github/workflows/main.yml rename to .github/workflows/macos.yml index 1663e4051..3348d48b9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/macos.yml @@ -1,29 +1,27 @@ -name: macOS build +name: macOS Build on: push: branches: - dev - - patch** - - newlocallab + - releases + tags: + - '[0-9]+.*' pull_request: branches: - dev - - newlocallab - release: - types: - - created + workflow_dispatch: jobs: build: - runs-on: macos-10.15 + runs-on: macos-11 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - 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++@2 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 llvm shared-mime-info | tee -a depslog date -u echo "----====Pourage====----" cat depslog | grep Pouring @@ -50,6 +48,7 @@ jobs: -DCACHE_NAME_SUFFIX="${RAW_THERAPEE_MAJOR}.${RAW_THERAPEE_MINOR}-${REF}" \ -DPROC_TARGET_NUMBER="1" \ -DPROC_LABEL="generic processor" \ + -DCMAKE_OSX_ARCHITECTURES=$(uname -m) \ -DWITH_LTO="OFF" \ -DLENSFUNDBDIR="/Applications/RawTherapee.app/Contents/Resources/share/lensfun" \ -DCMAKE_C_COMPILER=clang \ @@ -63,8 +62,10 @@ jobs: -DOpenMP_libomp_LIBRARY=/usr/local/lib/libomp.dylib \ -DCMAKE_AR=/usr/bin/ar \ -DCMAKE_RANLIB=/usr/bin/ranlib \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ + -DOSX_CONTINUOUS=ON \ .. + curl -L https://github.com/Homebrew/homebrew-core/raw/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -o libomp.rb && brew install --formula libomp.rb zsh -c 'echo "Configured in $(printf "%0.2f" $(($[$(date +%s)-$(cat configstamp)]/$((60.))))) minutes"' - name: Compile RawTherapee run: | @@ -78,15 +79,21 @@ jobs: zsh date +%s > build/bundlestamp && date -u && cd build export REF=${GITHUB_REF##*/} && export LOCAL_PREFIX=/usr && sudo make macosx_bundle - export ARTIFACT=(RawTherapee*.zip) + export ARTIFACT=(RawTherapee*${CMAKE_BUILD_TYPE}.zip) echo "=== artifact: ${ARTIFACT}" # defining environment variables for next step as per # https://github.com/actions/starter-workflows/issues/68 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"' + printf '%s\n' \ + "REF: ${REF}" \ + "ARTIFACT: ${ARTIFACT}" \ + "ARTIFACT_PATH: ${ARTIFACT_PATH}" \ + "ARTIFACT_FILE: ${ARTIFACT_FILE}" \ + "PUBLISH_NAME: ${PUBLISH_NAME}" exit - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: ${{env.ARTIFACT_FILE}} path: ${{env.ARTIFACT_PATH}} @@ -94,3 +101,11 @@ jobs: run: | date -u zsh -c 'echo "Build completed in $(printf "%0.2f" $(($[$(date +%s)-$(cat build/stamp)]/$((60.))))) minutes"' + + - name: Publish artifacts + uses: softprops/action-gh-release@v1 + if: ${{github.ref_type == 'tag' || github.ref_name == 'dev'}} + with: + tag_name: nightly-github-actions + files: | + ${{env.ARTIFACT_PATH}} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e6c03a014..49fdf5999 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -3,6 +3,7 @@ on: push: branches: - dev + - releases tags: - '[0-9]+.*' pull_request: @@ -93,6 +94,8 @@ jobs: - name: Bundle dependencies run: | + echo "Listing shared library dependencies." + ldd "./build/${{matrix.build_type}}/rawtherapee.exe" echo "Getting workspace path." export BUILD_DIR="$(pwd)/build/${{matrix.build_type}}" echo "Build directory is '$BUILD_DIR'." @@ -119,6 +122,7 @@ jobs: "libexpat-1.dll" \ libffi-*.dll \ "libfftw3f-3.dll" \ + "libfftw3f_omp-3.dll" \ "libfontconfig-1.dll" \ "libfreetype-6.dll" \ "libfribidi-0.dll" \ @@ -154,11 +158,12 @@ jobs: "libpixman-1-0.dll" \ "libpng16-16.dll" \ "librsvg-2-2.dll" \ + "libsharpyuv-0.dll" \ "libsigc-2.0-0.dll" \ "libstdc++-6.dll" \ "libsystre-0.dll" \ "libthai-0.dll" \ - "libtiff-5.dll" \ + "libtiff-6.dll" \ "libtre-5.dll" \ "libwebp-7.dll" \ "libwinpthread-1.dll" \ @@ -201,7 +206,7 @@ jobs: echo "Creating GTK settings.ini." mkdir -p "$BUILD_DIR/share/gtk-3.0/" - echo '[Settings] gtk-button-images=1' > "$BUILD_DIR/share/gtk-3.0/settings.ini" + echo -e '[Settings]\ngtk-button-images=1' > "$BUILD_DIR/share/gtk-3.0/settings.ini" - name: Create installer if: ${{matrix.build_type == 'release' && (github.ref_type == 'tag' || github.ref_name == 'dev')}} diff --git a/AUTHORS.txt b/AUTHORS.txt index 471bf3da4..4fb664fa5 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -6,6 +6,7 @@ Project initiator: Development contributors, in last name alphabetical order: Roel Baars + Richard E Barber Martin Burri Pierre Cabrera Javier Celaya @@ -69,6 +70,7 @@ Other contributors (profiles, ideas, mockups, testing, forum activity, translati Wim ter Meer Alberto Righetto Kostia (Kildor) Romanov + Henning Sidow Kalle Söderman Wayne Sutton Johan Thor @@ -76,3 +78,4 @@ Other contributors (profiles, ideas, mockups, testing, forum activity, translati TooWaBoo Franz Trischberger Colin Walker + Martin Werner diff --git a/CMakeLists.txt b/CMakeLists.txt index edcfae943..e13cb53d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,9 @@ option(OSX_DEV_BUILD "Generate macOS development builds" OFF) # On macOS, optionally generate the final zip artifact file without version in the name for nightly upload purposes. option(OSX_NIGHTLY "Generate a generically-named zip" OFF) +# On macOS, optionally generate RawTherapee__macOS_.zip for the CI +option(OSX_CONTINUOUS "Generate a generically-named zip for CI" OFF) + # Generate a universal macOS build option(OSX_UNIVERSAL "Generate a universal app" OFF) @@ -94,14 +97,13 @@ option(OSX_UNIVERSAL "Generate a universal app" OFF) if(OSX_UNIVERSAL) if(NOT "${OSX_UNIVERSAL_URL}") if(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") - set(OSX_UNIVERSAL_URL "https://kd6kxr.keybase.pub/RawTherapee_macOS_x86_64_latest.zip" CACHE STRING "URL of x86_64 app for lipo") + set(OSX_UNIVERSAL_URL "file:///rawtherapee/latest/RawTherapee_macOS_x86_64_latest.zip" CACHE STRING "URL of x86_64 app for lipo") else() - set(OSX_UNIVERSAL_URL "https://kd6kxr.keybase.pub/RawTherapee_macOS_arm64_latest.zip" CACHE STRING "URL of arm64 app for lipo") + set(OSX_UNIVERSAL_URL "file:///rawtherapee/latest/RawTherapee_macOS_arm64_latest.zip" CACHE STRING "URL of arm64 app for lipo") endif() endif() endif() - # 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: diff --git a/README.md b/README.md index ae9efd9c8..64f4d08aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ -![RawTherapee logo](https://www.rawtherapee.com/images/logos/rawtherapee_logo_discuss.png) + + + + RawTherapee logo + + +![RawTherapee screenshot](http://rawtherapee.com/images/carousel/100_rt59_provence_local_maskxxx.jpg) RawTherapee is a powerful, cross-platform raw photo processing program, released as [libre software](https://en.wikipedia.org/wiki/Free_software) under the [GNU General Public License Version 3](https://opensource.org/licenses/gpl-3.0.html). It is written mostly in C++ using a [GTK+](https://www.gtk.org) front-end. It uses a patched version of [dcraw](https://www.dechifro.org/dcraw/) for reading raw files, with an in-house solution which adds the highest quality support for certain camera models unsupported by dcraw and enhances the accuracy of certain raw files already supported by dcraw. It is notable for the advanced control it gives the user over the demosaicing and development process. diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index eb8d96379..510847c8a 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,21 +1,14 @@ -RAWTHERAPEE 5.8-dev RELEASE NOTES +RAWTHERAPEE 5.9-dev RELEASE NOTES This is a development version of RawTherapee. We update the code almost daily. Every few months, once enough changes have accumulated and the code is stabilized, we make a new official release. Every code change between these releases is known as a "development" version, and this is one of them. + + +IN GENERAL + Start by reading the "Getting Started" article on RawPedia: https://rawpedia.rawtherapee.com/ -While we only commit tested and relatively stable code and so the development versions should be fairly stable, you should be aware that: -- Development versions only had limited testing, so there may be bugs unknown to us. -- You should report these bugs so that they get fixed for the next stable release. See - https://rawpedia.rawtherapee.com/How_to_write_useful_bug_reports -- The way new tools work in the development versions is likely to change as we tweak and tune them, so your processing profiles may produce different results when used in a future stable version. -- Bugs present in the stable versions get fixed in the development versions, and make it into the next stable version when we make a new official release. That means that in some ways the development versions can be "more stable" than the latest stable release. At the same time, new features may introduce new bugs. This is a trade-off you should be aware of. - - - -NEWS RELEVANT TO PHOTOGRAPHERS - RawTherapee supports most raw formats, including Pentax and Sony Pixel Shift, Canon Dual-Pixel, and those from Foveon and X-Trans sensors. If you're wondering whether it supports your camera's raw format, first download RawTherapee and try for yourself. If a raw format is not supported it will either not open, or the preview in the Editor tab will appear black, white, or have a strong color cast - usually magenta. In that case, read the "Adding Support for New Raw Formats" RawPedia article. @@ -25,15 +18,21 @@ In order to use RawTherapee efficiently you should know that: - To change slider values or drop-down list items with the mouse scroll-wheel, hold the Shift key. This is so that you can safely scroll the panels without accidentally changing a slider or other tool setting. - All curves support the Shift and Ctrl keys while dragging a point. Shift+drag makes the point snap to a meaningful axis (top, bottom, diagonal, other), while Ctrl+drag makes your mouse movement super-fine for precise point positioning. - There are many keyboard shortcuts which make working with RawTherapee much faster and give you greater control. Make sure you familiarize yourself with them on RawPedia's "Keyboard Shortcuts" page! +- All sliders support a fine-tuning mode which you can toggle by pressing the Shift key while dragging a slider. + + + +NEW FEATURES SINCE 5.9 -New features since 5.8: - TODO +- Added or improved support for cameras, raw formats and color profiles: + - TODO NEWS RELEVANT TO PACKAGE MAINTAINERS -New since 5.8: +New since 5.9: - TODO In general: @@ -74,18 +73,6 @@ https://discuss.pixls.us/c/software/rawtherapee -LIVE CHAT WITH USERS AND DEVELOPERS - -Network: freenode -Server: chat.freenode.net -Channel: #rawtherapee - -You can use freenode webchat to communicate without installing anything: -https://webchat.freenode.net/?randomnick=1&channels=rawtherapee&prompt=1 -More information here: https://rawpedia.rawtherapee.com/IRC - - - REVISION HISTORY The complete changelog is available at: diff --git a/com.rawtherapee.RawTherapee.appdata.xml b/com.rawtherapee.RawTherapee.appdata.xml index f7d588684..7e4c0b3a5 100644 --- a/com.rawtherapee.RawTherapee.appdata.xml +++ b/com.rawtherapee.RawTherapee.appdata.xml @@ -22,6 +22,7 @@ https://rawpedia.rawtherapee.com/Main_Page#Localization rawtherapee.desktop + diff --git a/rtdata/dcpprofiles/FUJIFILM DBP for GX680.dcp b/rtdata/dcpprofiles/FUJIFILM DBP for GX680.dcp new file mode 100644 index 000000000..dcfc174c7 Binary files /dev/null and b/rtdata/dcpprofiles/FUJIFILM DBP for GX680.dcp differ diff --git a/rtdata/images/splash.svg b/rtdata/images/splash.svg index 1e7c9f745..a840aac4d 100644 --- a/rtdata/images/splash.svg +++ b/rtdata/images/splash.svg @@ -7,12 +7,13 @@ viewBox="0 0 160 99.999999" version="1.1" id="svg783" - inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)" sodipodi:docname="splash.svg" inkscape:export-filename="/tmp/splash.png" inkscape:export-xdpi="96" inkscape:export-ydpi="96" enable-background="new" + xml:space="preserve" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" @@ -20,168 +21,117 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" - xmlns:dc="http://purl.org/dc/elements/1.1/"> - RawTherapee splash screen - - RawTherapee splash screen - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RawTherapee splash screen - - - - RawTherapee splash screen - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="path1801" /> diff --git a/rtdata/images/splash_template.svg b/rtdata/images/splash_template.svg index b6b42d07a..f5424e7cc 100644 --- a/rtdata/images/splash_template.svg +++ b/rtdata/images/splash_template.svg @@ -7,7 +7,7 @@ viewBox="0 0 160 99.999999" version="1.1" id="svg783" - inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)" sodipodi:docname="splash_template.svg" inkscape:export-filename="/tmp/splash.png" inkscape:export-xdpi="96" @@ -151,10 +151,10 @@ style="stop-color:#feab27;stop-opacity:1;" /> + width="157.40977mm" + inkscape:showpageshadow="2" + inkscape:deskcolor="#d1d1d1"> + + + RawTherapee splash screen + + + + + + + + + 8 + y="252.72681">9 GNU GPLv3 + y="277.12344">GNU GPLv3 + style="font-size:21.3333px;line-height:1.25;font-family:'Eras BQ';-inkscape-font-specification:'Eras BQ';white-space:pre;shape-inside:url(#rect181038);display:inline" /> PrerequisitesPrerequisites + id="tspan17771"> Obtain and install the font family ITC Eras Std. + id="tspan17775">Obtain and install the font family ITC Eras Std. + id="tspan17779"> DetailsDetails + id="tspan17785"> The color wheel is copied from rt-logo.svg and a glow filter is added + id="tspan17789">The color wheel is copied from rt-logo.svg and a glow filter is added to each segment and the wheel as a whole. + id="tspan17793">to each segment and the wheel as a whole. "Raw": font ITC Eras Ultra-Bold, 60 pt, -3 px letter spacing + id="tspan17797">"Raw": font ITC Eras Ultra-Bold, 60 pt, -3 px letter spacing "Therapee": font ITC Eras Medium, 60 pt, +1,5 pt letter spacing + id="tspan17801">"Therapee": font ITC Eras Medium, 60 pt, +1,5 pt letter spacing Version (big number): ITC Eras Bold, 58 pt, skewed -3° + id="tspan17805">Version (big number): ITC Eras Bold, 58 pt, skewed -3° Version (period + small number): ITC Eras Bold, 34 pt, skewed -3° + id="tspan17809">Version (period + small number): ITC Eras Bold, 34 pt, skewed -3° Release-type: ITC Eras Bold, 16 pt, skewed -3° + id="tspan17813">Release-type: ITC Eras Bold, 16 pt, skewed -3° + id="tspan17817"> PublishingPublishing + id="tspan17823"> 1. To prepare a splash screen for deployment, select all text and 1. To prepare a splash screen for deployment, select all text and choose choose Path > Object to Path. + id="tspan17833">Path > Object to Path. 2. Change release type text to whatever is required, or hide the layer 2. Change release type text to whatever is required, or hide the layer "Release type" entirely. + id="tspan17841">"Release type" entirely. 3. Remove this text field. + id="tspan17845">3. Remove this text field. 44. Save as "splash.svg" into "./rtdata/images/svg". + id="tspan17851">. Save as "splash.svg" into "./rtdata/images/svg". + id="tspan17855"> RawTherapee splash screen design 1.5 (March 2022) + id="tspan17859">RawTherapee splash screen design 1.5 (March 2022) www.rawtherapee.com + id="tspan17863">www.rawtherapee.com Gestión de color,\n- cuando se visualiza en una pantalla que usa el perfil de salida actual, si no se ha establecido un perfil de impresora. -TC_PRIM_BLUX;Bx -TC_PRIM_BLUY;By -TC_PRIM_GREX;Gx -TC_PRIM_GREY;Gy -TC_PRIM_REDX;Rx -TC_PRIM_REDY;Ry +TC_PRIM_BLUX;Azul X +TC_PRIM_BLUY;Azul Y +TC_PRIM_GREX;Verde X +TC_PRIM_GREY;Verde Y +TC_PRIM_REDX;Rojo X +TC_PRIM_REDY;Rojo Y THRESHOLDSELECTOR_B;Inferior THRESHOLDSELECTOR_BL;Inferior-izquierda THRESHOLDSELECTOR_BR;Inferior-derecha @@ -2140,7 +2161,7 @@ TP_COLORAPP_ALGO_TOOLTIP;Permite escoger entre subconjuntos de parámetros o tod TP_COLORAPP_BADPIXSL;Filtro de píxels calientes/muertos TP_COLORAPP_BADPIXSL_TOOLTIP;Supresión de píxels calientes/muertos (de un color brillante).\n0 = Sin efecto\n1 = Mediana\n2 = Gaussiano.\nAlternativamente, ajusta la imagen para evitar sombras muy oscuras.\n\nEstos artefactos se deben a limitaciones de CIECAM02. TP_COLORAPP_BRIGHT;Brillo (Q) -TP_COLORAPP_BRIGHT_TOOLTIP;El Brillo en CIECAM02/16 es la cantidad de luz percibida que emana de un estímulo, y difiere del brillo de L*a*b* y RGB. +TP_COLORAPP_BRIGHT_TOOLTIP;El Brillo en CIECAM es la cantidad de luz percibida que emana de un estímulo. Difiere del brillo de L*a*b* y RGB. TP_COLORAPP_CAT02ADAPTATION_TOOLTIP;Si se ajusta manualmente, se recomiendan valores por encima de 65. TP_COLORAPP_CATCLASSIC;Clásico TP_COLORAPP_CATMET_TOOLTIP;Clásico: funcionamiento tradicional de CIECAM. Las transformaciones de adaptación cromática se aplican separadamente en «Condiciones de la escena» e iluminante básico por un lado, y en el iluminante básico y «Condiciones de entorno» por otro.\n\nSimétrico: La adaptación cromática se basa en el balance de blancos. Los ajustes «Condiciones de la escena», «Ajustes de imagen» y «Condiciones de entorno» se neutralizan.\n\nMezcla: Como la opción «Clásico», pero en este caso, la adaptación cromática se basa en el balance de blancos. @@ -2149,29 +2170,29 @@ TP_COLORAPP_CATSYMGEN;Automático simétrico TP_COLORAPP_CATSYMSPE;Mezcla TP_COLORAPP_CHROMA;Cromaticidad (C) TP_COLORAPP_CHROMA_M;Colorido (M) -TP_COLORAPP_CHROMA_M_TOOLTIP;El colorido en CIECAM02/16 es la cantidad percibida de matiz en relación al gris, un indicador de que un estímulo parece estar más o menos coloreado. +TP_COLORAPP_CHROMA_M_TOOLTIP;El colorido en CIECAM es la cantidad percibida de matiz en relación al gris, un indicador de que un estímulo parece estar más o menos coloreado. TP_COLORAPP_CHROMA_S;Saturación (S) -TP_COLORAPP_CHROMA_S_TOOLTIP;La Saturación en CIECAM02/16 corresponde al color de un estímulo en relación a su propio brillo. Difiere de la saturación L*a*b* y RGB. -TP_COLORAPP_CHROMA_TOOLTIP;La Cromaticidad en CIECAM02/16 corresponde al color de un estímulo relativo a la claridad de un estímulo que parece blanco bajo idénticas condiciones. Difiere de la cromaticidad L*a*b* y RGB. -TP_COLORAPP_CIECAT_DEGREE;Adaptación CAT02 +TP_COLORAPP_CHROMA_S_TOOLTIP;La Saturación en CIECAM corresponde al color de un estímulo en relación a su propio brillo. Difiere de la saturación L*a*b* y RGB. +TP_COLORAPP_CHROMA_TOOLTIP;La Cromaticidad en CIECAM corresponde al color de un estímulo relativo a la claridad de un estímulo que parece blanco bajo idénticas condiciones. Difiere de la cromaticidad L*a*b* y RGB. +TP_COLORAPP_CIECAT_DEGREE;Adaptación TP_COLORAPP_CONTRAST;Contraste (J) TP_COLORAPP_CONTRAST_Q;Contraste (Q) -TP_COLORAPP_CONTRAST_Q_TOOLTIP;El Contraste (Q) en CIECAM02/16 se basa en el brillo. Difiere del contraste en L*a*b* y RGB. -TP_COLORAPP_CONTRAST_TOOLTIP;El Contraste (J) en CIECAM02/16 se basa en la claridad. Difiere del contraste en L*a*b* y RGB. +TP_COLORAPP_CONTRAST_Q_TOOLTIP;El Contraste (Q) en CIECAM se basa en el brillo. Difiere del contraste en L*a*b* y RGB. +TP_COLORAPP_CONTRAST_TOOLTIP;El Contraste (J) en CIECAM se basa en la claridad. Difiere del contraste en L*a*b* y RGB. TP_COLORAPP_CURVEEDITOR1;Curva tonal 1 -TP_COLORAPP_CURVEEDITOR1_TOOLTIP;Muestra el histograma de L* (L*a*b*) antes de CIECAM02/16.\nSi la casilla «Mostrar histogramas de salida de CIECAM02/16 en curvas» está activada, muestra el histograma de J después de CIECAM02/16.\n\nJ no se muestra en el panel del histograma principal.\n\nPara la salida final, se puede consultar el panel del histograma principal. +TP_COLORAPP_CURVEEDITOR1_TOOLTIP;Muestra el histograma de L* (L*a*b*) antes de CIECAM.\nSi la casilla «Mostrar histogramas de salida de CIECAM en curvas» está activada, muestra el histograma de J después de CIECAM.\n\nJ no se muestra en el panel del histograma principal.\n\nPara la salida final, se puede consultar el panel del histograma principal. TP_COLORAPP_CURVEEDITOR2;Curva tonal 2 TP_COLORAPP_CURVEEDITOR2_TOOLTIP;El mismo uso que la primera curva tonal J(J). TP_COLORAPP_CURVEEDITOR3;Curva de color -TP_COLORAPP_CURVEEDITOR3_TOOLTIP;Ajusta la cromaticidad, la saturación o el colorido.\n\nMuestra el histograma de cromaticidad (L*a*b*) antes de CIECAM02/16.\nSi la casilla «Mostrar histogramas de salida de CIECAM02/16 en curvas» está activada, muestra el histograma de C, S o M después de CIECAM02/16.\n\nC, S y M no se muestran en el panel del histograma principal.\nPara la salida final, se puede consultar el panel del histograma principal. -TP_COLORAPP_DATACIE;Histogramas de salida CIECAM02/16 en curvas -TP_COLORAPP_DATACIE_TOOLTIP;Si está activado, los histogramas en las curvas CIECAM02/16 muestran los valores/rangos aproximados de J, y C, S o M después de los ajustes de CIECAM02/16.\nEsta selección no influye en el histograma principal.\n\nSi está desactivado, los histogramas en las curvas CIECAM02/16 muestran los valores L*a*b* antes de los ajustes de CIECAM02/16. +TP_COLORAPP_CURVEEDITOR3_TOOLTIP;Ajusta la cromaticidad, la saturación o el colorido.\n\nMuestra el histograma de cromaticidad (L*a*b*) antes de CIECAM.\nSi la casilla «Mostrar histogramas de salida de CIECAM en curvas» está activada, muestra el histograma de C, S o M después de CIECAM.\n\nC, S y M no se muestran en el panel del histograma principal.\nPara la salida final, se puede consultar el panel del histograma principal. +TP_COLORAPP_DATACIE;Histogramas de salida CIECAM en las curvas +TP_COLORAPP_DATACIE_TOOLTIP;Si está activado, los histogramas en las curvas CIECAM muestran los valores/rangos aproximados de J, y C, S o M después de los ajustes de CIECAM.\nEsta selección no influye en el histograma principal.\n\nSi está desactivado, los histogramas en las curvas CIECAM muestran los valores L*a*b* antes de los ajustes de CIECAM. TP_COLORAPP_DEGREE_TOOLTIP;CAT02/16 es una adaptación cromática. Convierte los valores de una imagen cuyo punto blanco es el de un iluminante dado (por ejemplo D65) a nuevos valores cuyo punto blanco es el del nuevo iluminante. Consúltese el Modelo de Punto Blanco (por ejemplo, D50 or D55). TP_COLORAPP_DEGREOUT_TOOLTIP;CAT02/16 es una adaptación cromática. Convierte los valores de una imagen cuyo punto blanco es el de un iluminante dado (por ejemplo D50) a nuevos valores cuyo punto blanco es el del nuevo iluminante. Consúltese el Modelo de Punto Blanco (por ejemplo D75). TP_COLORAPP_FREE;Temperatura+verde libres + CAT02/16 + [salida] -TP_COLORAPP_GAMUT;Control de rango de colores (L*a*b*) -TP_COLORAPP_GEN;Ajustes - Preselección -TP_COLORAPP_GEN_TOOLTIP;Este módulo está basado en el modelo de apariencia de color CIECAM, que se diseñó para simular mejor cómo la visión humana percibe los colores bajo diferentes condiciones de iluminación, por ejemplo, contra fondos diferentes.\n\nTiene en cuenta el entorno de cada color y modifica su apariencia para que sea lo más cercana posible a la percepción humana.\n\nTambién adapta la salida a las condiciones de visualización previstas (monitor, TV, proyector, impresora, etc.) de modo que la apariencia cromática se preserve para todos los entornos de escena y visualización. +TP_COLORAPP_GAMUT;Emplear el control de rango de colores en el modo L*a*b* +TP_COLORAPP_GEN;Ajustes +TP_COLORAPP_GEN_TOOLTIP;Este módulo está basado en los modelos de apariencia de color CIECAM, que se diseñaron para simular mejor cómo la visión humana percibe los colores bajo diferentes condiciones de iluminación, por ejemplo, contra fondos diferentes.\n\nTiene en cuenta el entorno de cada color y modifica su apariencia para que sea lo más cercana posible a la percepción humana.\n\nTambién adapta la salida a las condiciones de visualización previstas (monitor, TV, proyector, impresora, etc.) de modo que la apariencia cromática se preserve para todos los entornos de escena y visualización. TP_COLORAPP_HUE;Matiz (h) TP_COLORAPP_HUE_TOOLTIP;Matiz (h) es el grado en que un estímulo puede describirse como similar a un color descrito como rojo, verde, azul y amarillo. TP_COLORAPP_IL41;D41 @@ -2184,12 +2205,12 @@ TP_COLORAPP_ILA;Incandescente StdA 2856K TP_COLORAPP_ILFREE;Libre TP_COLORAPP_ILLUM;Iluminante TP_COLORAPP_ILLUM_TOOLTIP;Selecciona el iluminante más cercano a las condiciones de toma.\nEn general será D50, pero puede cambiar en función de la hora y la latitud. -TP_COLORAPP_LABEL;Apariencia de Color e Iluminación (CIECAM02/16) +TP_COLORAPP_LABEL;Apariencia de Color e Iluminación TP_COLORAPP_LABEL_CAM02;Ajustes de imagen TP_COLORAPP_LABEL_SCENE;Condiciones de la escena TP_COLORAPP_LABEL_VIEWING;Condiciones de visualización TP_COLORAPP_LIGHT;Claridad (J) -TP_COLORAPP_LIGHT_TOOLTIP;La Claridad en CIECAM02/16 es la claridad de un estímulo relativa a la claridad de un estímulo que parece blanco bajo condiciones de visualización similares. Difiere de la claridad en L*a*b* y RGB. +TP_COLORAPP_LIGHT_TOOLTIP;La Claridad en CIECAM es la claridad de un estímulo relativa a la claridad de un estímulo que parece blanco bajo condiciones de visualización similares. Difiere de la claridad en L*a*b* y RGB. TP_COLORAPP_MEANLUMINANCE;Luminancia media (Yb%) TP_COLORAPP_MOD02;CIECAM02 TP_COLORAPP_MOD16;CIECAM16 @@ -2202,14 +2223,13 @@ TP_COLORAPP_NEUTRAL_TOOLTIP;Restablece todos los deslizadores, casillas de verif TP_COLORAPP_RSTPRO;Protección de rojo y tonos de piel TP_COLORAPP_RSTPRO_TOOLTIP;La Protección de rojo y tonos de piel afecta tanto a los deslizadores como a las curvas. TP_COLORAPP_SOURCEF_TOOLTIP;Corresponde a las condiciones de toma y cómo llevar las condiciones y los datos a una zona «normal». «Normal» significa aquí condiciones y datos promedio o estándar, es decir, sin tener en cuenta las correcciones CIECAM. -TP_COLORAPP_SURROUND;Entorno -TP_COLORAPP_SURROUNDSRC;Entorno - Iluminación de escena +TP_COLORAPP_SURROUND;Entorno de visualización +TP_COLORAPP_SURROUNDSRC;Entorno (Iluminación de escena) TP_COLORAPP_SURROUND_AVER;Promedio TP_COLORAPP_SURROUND_DARK;Oscuro TP_COLORAPP_SURROUND_DIM;Luz tenue TP_COLORAPP_SURROUND_EXDARK;Muy oscuro TP_COLORAPP_SURROUND_TOOLTIP;Cambia los tonos y colores teniendo en cuenta las condiciones de visualización del dispositivo de salida.\n\nPromedio: Entorno de luz promedio (estándar). La imagen no cambiará.\n\nLuz tenue: Entorno con luz tenue (TV). La imagen se volverá un poco oscura.\n\nOscuro: Entorno oscuro (proyector). La imagen se volverá más oscura.\n\nMuy oscuro: Entorno muy oscuro. La imagen se volverá muy oscura. -TP_COLORAPP_SURSOURCE;Entorno origen TP_COLORAPP_SURSOURCE_TOOLTIP;Cambia tonos y colores para tener en cuenta las condiciones de la escena.\n\nPromedio: Entorno de luz promedio (estándar). La imagen no cambiará.\n\nTenue: Entorno tenue. La imagen se volverá ligeramente brillante.\n\nOscuro: Entorno oscuro. La imagen se volverá más brillante.\n\nMuy oscuro: Entorno muy oscuro. La imagen se volverá muy brillante. TP_COLORAPP_TCMODE_BRIGHTNESS;Brillo TP_COLORAPP_TCMODE_CHROMA;Cromaticidad @@ -2221,9 +2241,9 @@ TP_COLORAPP_TCMODE_LIGHTNESS;Claridad TP_COLORAPP_TCMODE_SATUR;Saturación TP_COLORAPP_TEMP2_TOOLTIP;O bien modo simétrico, Temp = balance de blancos.\nO bien, se selecciona el iluminante, poniendo siempre Tinte=1.\n\nA Temp=2856 K\nD41 Temp=4100 K\nD50 Temp=5003 K\nD55 Temp=5503 K\nD60 Temp=6000 K\nD65 Temp=6504 K\nD75 Temp=7504 K TP_COLORAPP_TEMP_TOOLTIP;Para seleccionar un iluminante, se ajusta siempre Tinte=1.\n\nTemp A=2856 K\nTemp D50=5003 K\nTemp D55=5503 K\nTemp D65=6504 K\nTemp D75=7504 K -TP_COLORAPP_TONECIE;Mapeo tonal mediante CIECAM02 +TP_COLORAPP_TONECIE;Mapeo tonal mediante CIECAM TP_COLORAPP_TONECIE_TOOLTIP;Si esta opción está desactivada, el mapeo tonal se realiza en el espacio L*a*b*.\nSi está activada, el mapeo tonal se realiza mediante CIECAM02.\nLa herramienta Mapeo tonal debe estar activada para que este ajuste tenga efectos. -TP_COLORAPP_VIEWINGF_TOOLTIP;Tiene en cuenta el medio en el que se visualizará la imagen final (monitor, TV, proyector, impresora, ...), así como su entorno. Este proceso tomará los datos procedentes del proceso «Ajustes de imagen» y los «llevará» al medio de visualización, de tal modo que se tendrán en cuenta las condiciones de visualización. +TP_COLORAPP_VIEWINGF_TOOLTIP;Tiene en cuenta el medio en el que se visualizará la imagen final (monitor, TV, proyector, impresora, etc.), así como su entorno. Este proceso tomará los datos procedentes del proceso «Ajustes de imagen» y los «llevará» al medio de visualización, de tal modo que se tendrán en cuenta las condiciones de visualización. TP_COLORAPP_VIEWING_ABSOLUTELUMINANCE_TOOLTIP;Luminancia absoluta del entorno de visualización\n(normalmente 16 cd/m²). TP_COLORAPP_WBCAM;WB [RT+CAT02] + [salida] TP_COLORAPP_WBRT;WB [RT] + [salida] @@ -2919,6 +2939,7 @@ TP_LOCALLAB_JZHJZFRA;Curva Jz(Hz) TP_LOCALLAB_JZHUECIE;Rotación de matiz TP_LOCALLAB_JZLIGHT;Luminosidad TP_LOCALLAB_JZLOG;Codificación Log Jz +TP_LOCALLAB_JZLOGWBS_TOOLTIP;Los ajustes Ev de Negro y Ev de Blanco pueden ser diferentes, dependiendo de si se usa Codificación logarítmica o Sigmoide.\nEn el caso de Sigmoide, puede ser necesario un cambio (aumento en la mayoría de los casos) de Ev de Blanco, para obtener una mejor representación de las altas luces, el contraste y la saturación. TP_LOCALLAB_JZLOGWB_TOOLTIP;Si Auto está activado, calculará y ajustará los niveles Ev y la «luminancia media Yb%» en el área del punto de edición. Los valores resultantes se usarán en todas las operaciones Jz, incluyendo «Codificación Log Jz».\nTambién calcula la luminancia absoluta en el momento de la toma. TP_LOCALLAB_JZLOGYBOUT_TOOLTIP;Yb es la luminosidad relativa del fondo, expresada como un porcentaje de gris. Un 18% de gris corresponde a una luminosidad del fondo del 50%, expresada en CIE L.\nLos datos se basan en la luminosidad media de la imagen.\nSi se usa con la Codificación logarítmica, la luminosidad media se utilizará para determinar la cantidad de ganancia que se necesita aplicar a la señal antes de la codificación logarítimica. Los valores bajos de luminosidad media darán como resultado un aumento de la ganancia. TP_LOCALLAB_JZMODECAM_TOOLTIP;Jz (sólo en modo «Avanzado»). Sólo funcionará si el dispositivo de salida (monitor) es HDR (luminancia pico mayor que 100 cd/m², idealmente entre 4000 y 10000 cd/m², y luminancia del punto negro inferior a 0.005 cd/m²). Esto supone que: a) el espacio de conexión de perfiles ICC (ICC-PCS) para la pantalla usa Jzazbz (o XYZ), b) trabaja con precisión de números reales (de coma flotante), c) el monitor está calibrado (si es posible, con un rango de colores DCI-P3 o Rec-2020), d) la gamma usual (sRGB o BT709) se substituye por una función Cuantificadora Perceptual (CP). @@ -2979,6 +3000,8 @@ TP_LOCALLAB_LOGAUTOGRAY_TOOLTIP;Calcula automáticamente la «luminancia media» TP_LOCALLAB_LOGAUTO_TOOLTIP;Al pulsar este botón se calculará el «rango dinámico» y la «luminancia media» para las condiciones de la escena si está activada la casilla «Luminancia media automática (Yb%)».\nTambién se calcula la luminancia absoluta en el momento de la toma.\nPara ajustar los valores calculados automáticamente hay que volver a pulsar el botón. TP_LOCALLAB_LOGBASE_TOOLTIP;Valor predeterminado = 2.\nLos valores menores que 2 reducen la acción del algoritmo, haciendo las sombras más oscuras y las luces más brillantes.\nCon valores mayores que 2, las sombras son más grises y las luces son más desteñidas. TP_LOCALLAB_LOGCATAD_TOOLTIP;La adaptación cromática permite interpretar un color en función de su entorno espacio-temporal.\nEs útil cuando el balance de blancos está lejos de la referencia D50.\nAdapta los colores al iluminante del dispositivo de salida. +TP_LOCALLAB_LOGCIE;Codificación logarítmica en lugar de Sigmoide +TP_LOCALLAB_LOGCIE_TOOLTIP;Permite el uso de Ev de Negro, Ev de Blanco, Luminancia media de la escena (Yb%) y Luminancia media de la visualización (Yb%) para el mapeo tonal con Codificación logarítmica Q. TP_LOCALLAB_LOGCOLORFL;Colorido (M) TP_LOCALLAB_LOGCOLORF_TOOLTIP;Cantidad de matiz percibida en relación al gris.\nIndicador de que un estímulo parece más o menos coloreado. TP_LOCALLAB_LOGCONQL;Contraste (Q) @@ -3003,6 +3026,7 @@ TP_LOCALLAB_LOGREPART;Intensidad TP_LOCALLAB_LOGREPART_TOOLTIP;Permite ajustar la intensidad relativa de la imagen codificada logarítmicamente con respecto a la imagen original.\nNo afecta al componente Ciecam. TP_LOCALLAB_LOGSATURL_TOOLTIP;La Saturación (s) en CIECAM16 corresponde al color de un estímulo en relación a su propio brillo.\nActúa principalmente en tonos medios y luces. TP_LOCALLAB_LOGSCENE_TOOLTIP;Corresponde a las condiciones de toma. +TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Cambia los tonos y colores teniendo en cuenta las condiciones de la escena.\n\nPromedio: Condiciones de luz promedio (estándar). La imagen no cambiará.\n\nTenue: Condiciones de luz tenue. La imagen será ligeramente más brillante.\n\nOscuro: Condiciones de oscuridad. La imagen será más brillante. TP_LOCALLAB_LOGVIEWING_TOOLTIP;Corresponde al medio en el que se visualizará la imagen final (monitor, TV, proyector, impresora,..), así como su entorno. TP_LOCALLAB_LOG_TOOLNAME;Codificación logarítmica - 0 TP_LOCALLAB_LUM;Curvas LL - CC @@ -3068,7 +3092,6 @@ TP_LOCALLAB_MASKRESWAV_TOOLTIP;Usado para modular el efecto de los ajustes de Co TP_LOCALLAB_MASKUNUSABLE;Máscara desactivada (Máscara y modificaciones) TP_LOCALLAB_MASKUSABLE;Máscara activada (Máscara y modificaciones) TP_LOCALLAB_MASK_TOOLTIP;Se puede activar varias máscaras para una herramienta, activando otra herramienta y usando solamente la máscara (ajusta los deslizadores de la herramienta a 0 ).\n\nTambién es posible duplicar el punto RT y situarlo cerca del primer punto. Las pequeñas variaciones en las referencias del punto permiten hacer ajustes finos. -TP_LOCALLAB_MED;Medio TP_LOCALLAB_MEDIAN;Mediana baja TP_LOCALLAB_MEDIANITER_TOOLTIP;El número de iteraciones sucesivas llevadas a cabo por el filtro de mediana. TP_LOCALLAB_MEDIAN_TOOLTIP;Se puede elegir un valor de mediana en el rango de 3x3 a 9x9 píxels. Los valores altos aumentan la reducción de ruido y el difuminado. @@ -3480,9 +3503,9 @@ TP_RAWEXPOS_LINEAR;Corrección de punto blanco TP_RAWEXPOS_RGB;Rojo, Verde, Azul TP_RAWEXPOS_TWOGREEN;Vincular verdes TP_RAW_1PASSMEDIUM;1 paso (Markesteijn) -TP_RAW_2PASS;1 paso + fast +TP_RAW_2PASS;1 paso + rápido TP_RAW_3PASSBEST;3 pasos (Markesteijn) -TP_RAW_4PASS;3 pasos + fast +TP_RAW_4PASS;3 pasos + rápido TP_RAW_AHD;AHD TP_RAW_AMAZE;AMaZE TP_RAW_AMAZEBILINEAR;AMaZE+Bilineal @@ -3502,7 +3525,7 @@ TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP;Si la casilla está activada (recomendad TP_RAW_DUALDEMOSAICCONTRAST;Umbral de contraste TP_RAW_EAHD;EAHD TP_RAW_FALSECOLOR;Pasos de supresión de falso color -TP_RAW_FAST;Fast +TP_RAW_FAST;Rápido TP_RAW_HD;Umbral TP_RAW_HD_TOOLTIP;Los valores bajos hacen más agresiva la detección de píxels muertos/calientes, pero los falsos positivos pueden dar lugar a artefactos. Si se observa la aparición de cualquier artefacto al activar el filtro de píxel muerto/caliente, debe incrementarse gradualmente el umbral hasta que desaparezcan. TP_RAW_HPHD;HPHD @@ -3549,11 +3572,11 @@ TP_RAW_RCD;RCD TP_RAW_RCDBILINEAR;RCD+Bilineal TP_RAW_RCDVNG4;RCD+VNG4 TP_RAW_SENSOR_BAYER_LABEL;Sensor con matriz Bayer -TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;El método de 3 pasos da los mejores resultados (recomendado para imágenes de ISO baja).\nEl método de 1 paso es casi indistinguible del de 3 pasos para imágenes de ISO alta y es más rápido.\n+fast genera menos artefactos en zonas planas. +TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;El método de 3 pasos da los mejores resultados (recomendado para imágenes de ISO baja).\nEl método de 1 paso es casi indistinguible del de 3 pasos para imágenes de ISO alta y es más rápido.\n+rápido genera menos artefactos en zonas planas. TP_RAW_SENSOR_XTRANS_LABEL;Sensor con matriz X-Trans TP_RAW_VNG4;VNG4 TP_RAW_XTRANS;X-Trans -TP_RAW_XTRANSFAST;Fast X-Trans +TP_RAW_XTRANSFAST;X-Trans rápido TP_RESIZE_ALLOW_UPSCALING;Permitir aumento de tamaño TP_RESIZE_APPLIESTO;Se aplica a: TP_RESIZE_CROPPEDAREA;Área recortada @@ -4042,35 +4065,4 @@ ZOOMPANEL_ZOOMFITCROPSCREEN;Encajar recorte en la vista previa\nAtajo de teclado ZOOMPANEL_ZOOMFITSCREEN;Encajar la imagen entera en la vista previa\nAtajo de teclado: Alt-f ZOOMPANEL_ZOOMIN;Acercar\nAtajo de teclado: + ZOOMPANEL_ZOOMOUT;Alejar\nAtajo de teclado: - -xTP_LOCALLAB_LOGSURSOUR_TOOLTIP;Cambia los tonos y colores para tener en cuenta las condiciones de la escena.\n\nPromedio: Entorno de luz promedio (estándar). La imagen no cambiará.\n\nTenue: Entorno tenue. La imagen aumentará su brillo ligeramente. -//HISTORY_MSG_1099;Local - Curva Hz(Hz) -!!!!!!!!!!!!!!!!!!!!!!!!! -! Untranslated keys follow; remove the ! prefix after an entry is translated. -!!!!!!!!!!!!!!!!!!!!!!!!! - -!HISTORY_MSG_446;--unused-- -!HISTORY_MSG_447;--unused-- -!HISTORY_MSG_448;--unused-- -!HISTORY_MSG_450;--unused-- -!HISTORY_MSG_451;--unused-- -!HISTORY_MSG_454;--unused-- -!HISTORY_MSG_455;--unused-- -!HISTORY_MSG_456;--unused-- -!HISTORY_MSG_458;--unused-- -!HISTORY_MSG_459;--unused-- -!HISTORY_MSG_460;--unused-- -!HISTORY_MSG_461;--unused-- -!HISTORY_MSG_463;--unused-- -!HISTORY_MSG_466;--unused-- -!HISTORY_MSG_467;--unused-- -!HISTORY_MSG_470;--unused-- -!HISTORY_MSG_1149;Local - Q Sigmoid -!HISTORY_MSG_1150;Local - Log encoding Q instead Sigmoid Q -!ICCPROFCREATOR_ILL_63;D63 : DCI-P3 Theater -!ICCPROFCREATOR_PRIM_DCIP3;DCI-P3 -!PARTIALPASTE_SPOT;Spot removal -!TP_LOCALLAB_JZLOGWBS_TOOLTIP;Black Ev and White Ev adjustments can be different depending on whether Log encoding or Sigmoid is used.\nFor Sigmoid, a change (increase in most cases) of White Ev may be necessary to obtain a better rendering of highlights, contrast and saturation. -!TP_LOCALLAB_LOGCIE;Log encoding instead of Sigmoid -!TP_LOCALLAB_LOGCIE_TOOLTIP;Allows you tu use Black Ev, White Ev, Scene Mean luminance(Yb%) and Viewing Mean luminance(Yb%) for tone-mapping using Log encoding Q. -!TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Changes tones and colors to take into account the Scene conditions.\n\nAverage: Average light conditions (standard). The image will not change.\n\nDim: Dim conditions. The image will become slightly brighter.\n\nDark: Dark conditions. The image will become more bright. diff --git a/rtdata/languages/Japanese b/rtdata/languages/Japanese index 913ee8112..0f35036db 100644 --- a/rtdata/languages/Japanese +++ b/rtdata/languages/Japanese @@ -1,15 +1,4 @@ -#01 2011-05-15 a3novy -#02 2011-11-13 a3novy -#03 2011-11-20 a3novy -#04 2011-12-03 a3novy -#05 2012-02-11 a3novy -#06 2012-04-04 a3novy -#07 2012-07-12 a3novy -#08 2012-12-22 a3novy -#09 2013-04-01 a3novy -#10 2013-04-19 a3novy -#11 2020-06-24 Yz2house -#12 2022-06-04 Yz2house +#Last update 10-12-2022 ABOUT_TAB_BUILD;バージョン ABOUT_TAB_CREDITS;クレジット @@ -19,9 +8,9 @@ ABOUT_TAB_SPLASH;スプラッシュ ADJUSTER_RESET_TO_DEFAULT;クリック - デフォルト値にリセット\nCtrl+クリック - 初期値にリセット BATCH_PROCESSING;バッチ処理 CURVEEDITOR_AXIS_IN;入力値: -CURVEEDITOR_AXIS_LEFT_TAN;LT: +CURVEEDITOR_AXIS_LEFT_TAN;左正接: CURVEEDITOR_AXIS_OUT;出力値: -CURVEEDITOR_AXIS_RIGHT_TAN;RT: +CURVEEDITOR_AXIS_RIGHT_TAN;右正接: CURVEEDITOR_CATMULLROM;フレキシブル CURVEEDITOR_CURVE;カーブ CURVEEDITOR_CURVES;カーブ @@ -38,7 +27,7 @@ CURVEEDITOR_PARAMETRIC;パラメトリック CURVEEDITOR_SAVEDLGLABEL;カーブの保存... CURVEEDITOR_SHADOWS;シャドウ CURVEEDITOR_TOOLTIPCOPY;クリップボードに現在のカーブをコピー -CURVEEDITOR_TOOLTIPLINEAR;リニアにリセット +CURVEEDITOR_TOOLTIPLINEAR;線形にリセット CURVEEDITOR_TOOLTIPLOAD;ファイルからカーブを読み込む CURVEEDITOR_TOOLTIPPASTE;クリップボードからカーブを貼り付け CURVEEDITOR_TOOLTIPSAVE;現在のカーブを保存 @@ -52,7 +41,7 @@ DYNPROFILEEDITOR_ENTRY_TOOLTIP;整合性が悪い場合は、入力する際に" DYNPROFILEEDITOR_IMGTYPE_ANY;任意 DYNPROFILEEDITOR_IMGTYPE_HDR;HDR DYNPROFILEEDITOR_IMGTYPE_PS;ピクセルシフト -DYNPROFILEEDITOR_IMGTYPE_STD;標準え +DYNPROFILEEDITOR_IMGTYPE_STD;標準 DYNPROFILEEDITOR_MOVE_DOWN;下に移動 DYNPROFILEEDITOR_MOVE_UP;上に移動 DYNPROFILEEDITOR_NEW;新規 @@ -197,7 +186,7 @@ FILEBROWSER_SHOWCOLORLABEL5HINT;パープル・ラベルの画像を表示\nシ FILEBROWSER_SHOWDIRHINT;全ての絞り込みをクリア\nショートカット: d FILEBROWSER_SHOWEDITEDHINT;編集済み画像を表示\nショートカット: 7 FILEBROWSER_SHOWEDITEDNOTHINT;未編集画像を表示\nショートカット: 6 -FILEBROWSER_SHOWEXIFINFO;EXIF情報を表示\nショートカット: i\n\nシングル・エディタ・タブのショートカット: Alt-i +FILEBROWSER_SHOWEXIFINFO;EXIF情報を表示\nショートカット: i\n\nシングル編集タブのショートカット: Alt-i FILEBROWSER_SHOWNOTTRASHHINT;ゴミ箱の中にある画像だけを表示 FILEBROWSER_SHOWORIGINALHINT;元画像だけを表示\n\nファイル名は同じだが拡張子が異なる画像がある場合は、環境設定の中のファイルブラウザタブにある拡張子リストの上位に位置する拡張子を持った画像を元画像とする。 FILEBROWSER_SHOWRANK1HINT;1つ星ランクを表示\nショートカット: 1 @@ -212,8 +201,8 @@ FILEBROWSER_SHOWUNCOLORHINT;カラー・ラベルのない画像を表示\nシ FILEBROWSER_SHOWUNRANKHINT;ランクなし画像を表示\nショートカット: 0 FILEBROWSER_THUMBSIZE;サムネイルのサイズ FILEBROWSER_UNRANK_TOOLTIP;ランクなし\nショートカット: Shift-0 -FILEBROWSER_ZOOMINHINT;サムネイルサイズの拡大\nショートカット: +\n\nシングル・エディタ・タブのショートカット: Alt-+ -FILEBROWSER_ZOOMOUTHINT;サムネイルサイズの縮小\nショートカット: -\n\nシングル・エディタ・タブのショートカット: Alt-- +FILEBROWSER_ZOOMINHINT;サムネイルサイズの拡大\nショートカット: +\n\nシングル編集タブのショートカット: Alt-+ +FILEBROWSER_ZOOMOUTHINT;サムネイルサイズの縮小\nショートカット: -\n\nシングル編集タブのショートカット: Alt-- FILECHOOSER_FILTER_ANY;全てのファイル FILECHOOSER_FILTER_COLPROF;カラープロファイル FILECHOOSER_FILTER_CURVE;カーブファイル @@ -311,14 +300,14 @@ HISTORY_MSG_40;色偏差 HISTORY_MSG_41;トーンカーブ1のモード HISTORY_MSG_42;トーンカーブ 2 HISTORY_MSG_43;トーンカーブ2のモード -HISTORY_MSG_48;DCPトーンカーブ使用 -HISTORY_MSG_49;色ノイズ低減 エッジの感度 +HISTORY_MSG_48;DCP トーンカーブ +HISTORY_MSG_49;DCP 光源 HISTORY_MSG_50;シャドウ/ハイライト -HISTORY_MSG_51;ハイライト -HISTORY_MSG_52;シャドウ -HISTORY_MSG_53;ハイライト トーンの幅 -HISTORY_MSG_54;シャドウ トーンの幅 -HISTORY_MSG_56;シャドウ/ハイライト 半径 +HISTORY_MSG_51;S/H - ハイライト +HISTORY_MSG_52;S/H - シャドウ +HISTORY_MSG_53;S/H - ハイライト トーンの幅 +HISTORY_MSG_54;S/H - シャドウ トーンの幅 +HISTORY_MSG_56;S/H - シャドウ/ハイライト 半径 HISTORY_MSG_57;90度 回転 HISTORY_MSG_58;左右反転 HISTORY_MSG_59;上下反転 @@ -339,9 +328,9 @@ HISTORY_MSG_74;リサイズ スケール HISTORY_MSG_75;リサイズ 方式 HISTORY_MSG_76;Exif メタデータ HISTORY_MSG_77;IPTC メタデータ -HISTORY_MSG_79;リサイズ幅 +HISTORY_MSG_79;リサイズ 幅 HISTORY_MSG_80;リサイズ 高さ -HISTORY_MSG_81;リサイズの有効・無効 +HISTORY_MSG_81;リサイズ HISTORY_MSG_82;プロファイル変更 HISTORY_MSG_84;パースペクティブの補正 HISTORY_MSG_85;レンズ補正 プロファイル @@ -426,39 +415,39 @@ HISTORY_MSG_170;自然な彩度 - カーブ HISTORY_MSG_171;L*a*b* LC カーブ HISTORY_MSG_172;LCの適用をレッドと肌色トーンだけに制限 HISTORY_MSG_173;ノイズ低減 - 細部の復元 -HISTORY_MSG_174;CIE色の見えモデル2002 -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_185;CAM02 - 色域制御 -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 - 色相角 -HISTORY_MSG_193;CAM02 - トーンカーブ 1 -HISTORY_MSG_194;CAM02 - トーンカーブ 2 -HISTORY_MSG_195;CAM02 - トーンカーブ 1 -HISTORY_MSG_196;CAM02 - トーンカーブ 2 -HISTORY_MSG_197;CAM02 - カラー・カーブ -HISTORY_MSG_198;CAM02 - カラー・カーブ -HISTORY_MSG_199;CAM02 - 出力のヒストグラムを表示 -HISTORY_MSG_200;CAM02 - トーンマッピング +HISTORY_MSG_174;色の見え&明るさ +HISTORY_MSG_175;CAL - 場面 - 色順応 +HISTORY_MSG_176;CAL - 観視 - 周囲 +HISTORY_MSG_177;CAL - 場面 - 絶対輝度 +HISTORY_MSG_178;CAL - 観視 - 絶対輝度 +HISTORY_MSG_179;CAL - 場面 - ホワイトポイントモデル +HISTORY_MSG_180;CAL - 編集 - 明度(J) +HISTORY_MSG_181;CAL - 編集 - 色度(C) +HISTORY_MSG_182;CAL - 場面 - 自動色順応 +HISTORY_MSG_183;CAL - 編集 - コントラスト(J) +HISTORY_MSG_184;CAL - 場面 - 周囲 +HISTORY_MSG_185;CAL - 色域制御 +HISTORY_MSG_186;CAL - 編集 - アルゴリズム +HISTORY_MSG_187;CAL - 編集 - レッドと肌色トーンを保護 +HISTORY_MSG_188;CAL - 編集 - 明るさ(Q) +HISTORY_MSG_189;CAL - 編集 - コントラスト(Q) +HISTORY_MSG_190;CAL - 編集 - 彩度(S) +HISTORY_MSG_191;CAL - 編集 - 鮮やかさ(M) +HISTORY_MSG_192;CAL - 編集 - 色相(h) +HISTORY_MSG_193;CAL - 編集 - トーンカーブ 1 +HISTORY_MSG_194;CAL - 編集 - トーンカーブ 2 +HISTORY_MSG_195;CAL - 編集 - トーンカーブ1のモード +HISTORY_MSG_196;CAL - 編集 - トーンカーブ2のモード +HISTORY_MSG_197;CAL - 編集 - カラーカーブ +HISTORY_MSG_198;CAL - 編集 - カラーカーブのモード +HISTORY_MSG_199;CAL - 編集 - ヒストグラムにCAMの出力を使う +HISTORY_MSG_200;CAL - 編集 - トーンマッピングにCAMを使う HISTORY_MSG_201;色差 レッド/グリーン HISTORY_MSG_202;色差 ブルー/イエロー HISTORY_MSG_203;ノイズ低減 - 方式 HISTORY_MSG_204;LMMSE 拡張処理 -HISTORY_MSG_205;CAM02 ホット/バッドピクセル -HISTORY_MSG_206;CAT02 - 自動で順応 +HISTORY_MSG_205;CAL ホット/バッドピクセル +HISTORY_MSG_206;CAL - 場面 - 自動で絶対輝度 HISTORY_MSG_207;フリンジ低減 - 色相カーブ HISTORY_MSG_208;ブルー/レッド イコライザ HISTORY_MSG_210;減光フィルター - 角度 @@ -487,7 +476,7 @@ HISTORY_MSG_232;白黒 ‘前の‘カーブのタイプ HISTORY_MSG_233;白黒 ‘後の‘カーブ HISTORY_MSG_234;白黒 ‘後の‘カーブのタイプ HISTORY_MSG_235;白黒 チャンネルミキサー 自動 -HISTORY_MSG_236;--未使用-- +HISTORY_MSG_236;--未使用の文字列-- HISTORY_MSG_237;白黒 チャンネルミキサー HISTORY_MSG_238;減光フィルター フェザー HISTORY_MSG_239;減光フィルター 強さ @@ -500,8 +489,8 @@ 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_249;詳細レベルによるコントラスト調整 - しきい値 -HISTORY_MSG_251;白黒 - アルゴリズム +HISTORY_MSG_249;CbDL しきい値 +HISTORY_MSG_251;白黒 アルゴリズム HISTORY_MSG_252;CbDL 肌色の目標/保護 HISTORY_MSG_253;CbDL アーティファクトを軽減 HISTORY_MSG_254;CbDL 肌色の色相 @@ -525,7 +514,7 @@ HISTORY_MSG_271;カラートーン調整 - ハイライトのブルー HISTORY_MSG_272;カラートーン調整 - バランス HISTORY_MSG_273;カラートーン調整 - SMHでカラーバランス HISTORY_MSG_276;カラートーン調整 - 不透明度 -HISTORY_MSG_277;カラートーン調整 - カーブをリセット +HISTORY_MSG_277;--未使用の文字列-- HISTORY_MSG_278;カラートーン調整 - 明度を維持 HISTORY_MSG_279;カラートーン調整 - シャドウ HISTORY_MSG_280;カラートーン調整 - ハイライト @@ -545,7 +534,7 @@ HISTORY_MSG_293;フィルムシミュレーション HISTORY_MSG_294;フィルムシミュレーション - 強さ HISTORY_MSG_295;フィルムシミュレーション - フィルム HISTORY_MSG_296;輝度ノイズ低減のカーブ -HISTORY_MSG_297;ノイズ低減 - 質 +HISTORY_MSG_297;ノイズ低減 - モード HISTORY_MSG_298;デッドピクセルフィルター HISTORY_MSG_299;色ノイズ低減のカーブ HISTORY_MSG_301;輝度ノイズの調整方法 @@ -671,7 +660,7 @@ HISTORY_MSG_421;レティネックス - ガンマ HISTORY_MSG_422;レティネックス - ガンマ HISTORY_MSG_423;レティネックス - 勾配 HISTORY_MSG_424;レティネックス - HLしきい値 -HISTORY_MSG_425;レティネックス - 対数の基数 +HISTORY_MSG_425;--未使用の文字列-- HISTORY_MSG_426;レティネックス - 色相イコライザ HISTORY_MSG_427;出力レンダリングの意図 HISTORY_MSG_428;モニターレンダリングの意図 @@ -692,44 +681,44 @@ 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_446;--未使用の文字列-- +HISTORY_MSG_447;--未使用の文字列-- +HISTORY_MSG_448;--未使用の文字列-- HISTORY_MSG_449;PS - ISOへの適合 -HISTORY_MSG_450;EvPixelShiftNreadIso -HISTORY_MSG_451;EvPixelShiftPrnu -HISTORY_MSG_452;PS - モーションを表示 +HISTORY_MSG_450;--未使用の文字列-- +HISTORY_MSG_451;--未使用の文字列-- +HISTORY_MSG_452;PS - 動体部分を表示 HISTORY_MSG_453;PS - マスクだけを表示 -HISTORY_MSG_454;EvPixelShiftAutomatic -HISTORY_MSG_455;EvPixelShiftNonGreenHorizontal -HISTORY_MSG_456;EvPixelShiftNonGreenVertical +HISTORY_MSG_454;--未使用の文字列-- +HISTORY_MSG_455;--未使用の文字列-- +HISTORY_MSG_456;--未使用の文字列-- HISTORY_MSG_457;PS - レッド/ブルーを確認 -HISTORY_MSG_458;EvPixelShiftStddevFactorRed -HISTORY_MSG_459;EvPixelShiftStddevFactorBlue -HISTORY_MSG_460;EvPixelShiftGreenAmaze -HISTORY_MSG_461;EvPixelShiftNonGreenAmaze +HISTORY_MSG_458;--未使用の文字列-- +HISTORY_MSG_459;--未使用の文字列-- +HISTORY_MSG_460;--未使用の文字列-- +HISTORY_MSG_461;--未使用の文字列-- HISTORY_MSG_462;PS - グリーンを確認 -HISTORY_MSG_463;EvPixelShiftRedBlueWeight -HISTORY_MSG_464;PS - モーションマスクをぼかす +HISTORY_MSG_463;--未使用の文字列-- +HISTORY_MSG_464;PS - 動体マスクをぼかす HISTORY_MSG_465;PS - ぼかしの半径 -HISTORY_MSG_466;EvPixelShiftSum -HISTORY_MSG_467;EvPixelShiftExp0 +HISTORY_MSG_466;--未使用の文字列-- +HISTORY_MSG_467;--未使用の文字列-- HISTORY_MSG_468;PS - 穴を埋める HISTORY_MSG_469;PS - メディアン -HISTORY_MSG_470;EvPixelShiftMedian3 -HISTORY_MSG_471;PS - 振れの補正 +HISTORY_MSG_470;--未使用の文字列-- +HISTORY_MSG_471;PS - 動体補正 HISTORY_MSG_472;PS - 境界を滑らかにする HISTORY_MSG_474;PS - 均等化 HISTORY_MSG_475;PS - 色チャンネルの均等化 -HISTORY_MSG_476;CAM02 - 観視環境の色温度 -HISTORY_MSG_477;CAM02 - 観視環境の色偏差 -HISTORY_MSG_478;CAM02 - 観視環境のYb -HISTORY_MSG_479;CAM02 - 観視環境のCAT02 -HISTORY_MSG_480;CAM02 - 観視環境のCAT02 自動 -HISTORY_MSG_481;CAM02 - 撮影環境の色温度 -HISTORY_MSG_482;CAM02 - 撮影環境の色偏差 -HISTORY_MSG_483;CAM02 - 撮影環境のYb -HISTORY_MSG_484;CAM02 - 撮影環境のYb 自動 +HISTORY_MSG_476;CAL - 観視 - 色温度 +HISTORY_MSG_477;CAL - 観視 - 色偏差 +HISTORY_MSG_478;CAL - 観視 - 平均輝度 +HISTORY_MSG_479;CAL - 観視 - 色順応 +HISTORY_MSG_480;CAL - 観視 - 色順応(自動) +HISTORY_MSG_481;CAL - 場面 - 色温度 +HISTORY_MSG_482;CAL - 場面 - 色偏差 +HISTORY_MSG_483;CAL - 場面 - 平均輝度 +HISTORY_MSG_484;CAL - 場面 - 平均輝度(自動) HISTORY_MSG_485;レンズ補正 HISTORY_MSG_486;レンズ補正 - カメラ HISTORY_MSG_487;レンズ補正 - レンズ @@ -824,7 +813,7 @@ HISTORY_MSG_576;ローカル - CbDL 複数のレベル HISTORY_MSG_577;ローカル - CbDL 色度 HISTORY_MSG_578;ローカル - CbDL しきい値 HISTORY_MSG_579;ローカル - CbDL スコープ -HISTORY_MSG_580;ローカル - ノイズ除去 +HISTORY_MSG_580;--未使用の文字列-- HISTORY_MSG_581;ローカル - ノイズ除去 輝度 番手の低いレベル HISTORY_MSG_582;ローカル - ノイズ除去 輝度 番手の高いレベル HISTORY_MSG_583;ローカル - ノイズ除去 ディテールの回復 @@ -867,9 +856,9 @@ HISTORY_MSG_620;ローカル - 色と明るさ ぼかし HISTORY_MSG_621;ローカル - 露光補正 反対処理 HISTORY_MSG_622;ローカル - 構造の除外 HISTORY_MSG_623;ローカル - 露光補正 色の補間 -HISTORY_MSG_624;ローカル - 色と明るさ 補正グリッド -HISTORY_MSG_625;ローカル - 色と明るさ 補正の強さ -HISTORY_MSG_626;ローカル - 色と明るさ 補正の方式 +HISTORY_MSG_624;ローカル - カラー補正グリッド +HISTORY_MSG_625;ローカル - 補正グリッドの強さ +HISTORY_MSG_626;ローカル - 補正グリッドの方式 HISTORY_MSG_627;ローカル - シャドウ/ハイライト HISTORY_MSG_628;ローカル - シャドウハイライト ハイライト HISTORY_MSG_629;ローカル - シャドウハイライト ハイライトトーンの幅 @@ -907,7 +896,7 @@ HISTORY_MSG_660;ローカル - CbDL 明瞭 HISTORY_MSG_661;ローカル - CbDL 残差のコントラスト HISTORY_MSG_662;ローカル - deNoise 輝度 細かい0 HISTORY_MSG_663;ローカル - deNoise 輝度 細かい2 -HISTORY_MSG_664;ローカル - CbDL ぼかし +HISTORY_MSG_664;--未使用の文字列-- HISTORY_MSG_665;ローカル - CbDL ブレンドのマスク HISTORY_MSG_666;ローカル - CbDL 半径のマスク HISTORY_MSG_667;ローカル - CbDL 色度のマスク @@ -986,16 +975,16 @@ 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_749;ローカル - レティネックス 深度 +HISTORY_MSG_750;ローカル - レティネックス モード 対数 - 線形 +HISTORY_MSG_751;ローカル - レティネックス 霞除去 彩度 +HISTORY_MSG_752;ローカル - レティネックス オフセット +HISTORY_MSG_753;ローカル - レティネックス 透過マップ +HISTORY_MSG_754;ローカル - レティネックス クリップ HISTORY_MSG_755;ローカル - TM マスクを使う HISTORY_MSG_756;ローカル - Exp 露光補正マスクのアルゴリズムを使う HISTORY_MSG_757;ローカル - Exp ラプラシアンマスク -HISTORY_MSG_758;ローカル - Reti ラプラシアンマスク +HISTORY_MSG_758;ローカル - レティネックス ラプラシアンマスク HISTORY_MSG_759;ローカル - Exp ラプラシアンマスク HISTORY_MSG_760;ローカル - Color ラプラシアンマスク HISTORY_MSG_761;ローカル - シャドウハイライト ラプラシアンマスク @@ -1011,7 +1000,7 @@ HISTORY_MSG_770;ローカル - Color コントラストカーブのマスク HISTORY_MSG_771;ローカル - Exp コントラストカーブのマスク HISTORY_MSG_772;ローカル - シャドウハイライト コントラストカーブのマスク HISTORY_MSG_773;ローカル - TM コントラストカーブのマスク -HISTORY_MSG_774;ローカル - Reti コントラストカーブのマスク +HISTORY_MSG_774;ローカル - レティネックス コントラストカーブのマスク HISTORY_MSG_775;ローカル - CBDL コントラストカーブのマスク HISTORY_MSG_776;ローカル - Blur Denoise コントラストカーブのマスク HISTORY_MSG_777;ローカル - Blur ローカルコントラストカーブのマスク @@ -1033,7 +1022,7 @@ HISTORY_MSG_792;ローカル - マスク 背景輝度 HISTORY_MSG_793;ローカル - シャドウハイライト TRCのガンマ HISTORY_MSG_794;ローカル - シャドウハイライト TRCのスロープ HISTORY_MSG_795;ローカル - マスク 復元したイメージの保存 -HISTORY_MSG_796;ローカル - 参考値の繰り返し +HISTORY_MSG_796;ローカル - 基準値の繰り返し HISTORY_MSG_797;ローカル - オリジナルとの融合方式 HISTORY_MSG_798;ローカル - 不透明度 HISTORY_MSG_799;ローカル - Color RGB トーンカーブ @@ -1078,9 +1067,9 @@ HISTORY_MSG_838;ローカル - 自然な彩度 階調 Hの強さ HISTORY_MSG_839;ローカル - ソフトウェアの難易度 HISTORY_MSG_840;ローカル - CL カーブ HISTORY_MSG_841;ローカル - LC カーブ -HISTORY_MSG_842;ローカル - ぼかしマスクの半径 -HISTORY_MSG_843;ローカル - ぼかしマスクのコントラストしきい値 -HISTORY_MSG_844;ローカル - ぼかしマスクのFFTW +HISTORY_MSG_842;ローカル - マスクぼかしの半径 +HISTORY_MSG_843;ローカル - マスクぼかしのコントラストしきい値 +HISTORY_MSG_844;ローカル - マスクぼかしのFFTW HISTORY_MSG_845;ローカル - 対数符号化 HISTORY_MSG_846;ローカル - 対数符号化 自動 HISTORY_MSG_847;ローカル - 対数符号化 情報源 @@ -1127,7 +1116,7 @@ HISTORY_MSG_890;ローカル - コントラスト ウェーブレット 階調 HISTORY_MSG_891;ローカル - コントラスト ウェーブレット 階調フィルタ HISTORY_MSG_892;ローカル - 対数符号化 階調の強さ HISTORY_MSG_893;ローカル - 対数符号化 階調の角度 -HISTORY_MSG_894;ローカル - 色と明るさ 色差のプレビュー +HISTORY_MSG_894;ローカル - 色と明るさ ΔEのプレビュー HISTORY_MSG_897;ローカル - コントラスト ウェーブレット ES 強さ HISTORY_MSG_898;ローカル - コントラスト ウェーブレット ES 半径 HISTORY_MSG_899;ローカル - コントラスト ウェーブレット ES ディテール @@ -1155,7 +1144,7 @@ HISTORY_MSG_920;ローカル - ウェーブレット シグマ LC HISTORY_MSG_921;ローカル - ウェーブレット 階調のシグマ LC2 HISTORY_MSG_922;ローカル - 白黒での変更 HISTORY_MSG_923;ローカル - 機能の複雑度モード -HISTORY_MSG_924;ローカル - 機能の複雑度モード +HISTORY_MSG_924;--未使用の文字列-- HISTORY_MSG_925;ローカル - カラー機能のスコープ HISTORY_MSG_926;ローカル - マスクのタイプを表示 HISTORY_MSG_927;ローカル - シャドウマスク @@ -1281,113 +1270,113 @@ HISTORY_MSG_1047;ローカル - シャドウ/ハイライトとトーンイコ HISTORY_MSG_1048;ローカル - ダイナミックレンジと露光補正 強さ HISTORY_MSG_1049;ローカル - トーンマッピング 強さ HISTORY_MSG_1050;ローカル - 対数符号化 色度 -HISTORY_MSG_1051;Local - 残差画像 ウェーブレット ガンマ -HISTORY_MSG_1052;Local - 残差画像 ウェーブレット スロープ -HISTORY_MSG_1053;Local - ノイズ除去 ガンマ -HISTORY_MSG_1054;Local - ウェーブレット ガンマ -HISTORY_MSG_1055;Local - 色と明るさ ガンマ -HISTORY_MSG_1056;Local - ダイナミックレンジ圧縮と露光補正 ガンマ -HISTORY_MSG_1057;Local - CIECAM 有効 -HISTORY_MSG_1058;Local - CIECAM 全体的な強さ -HISTORY_MSG_1059;Local - CIECAM 自動グレー -HISTORY_MSG_1060;Local - CIECAM 元画像のの平均輝度 -HISTORY_MSG_1061;Local - CIECAM 元画像の絶対輝度 -HISTORY_MSG_1062;Local - CIECAM 元画像の周囲環境 -HISTORY_MSG_1063;Local - CIECAM 彩度 -HISTORY_MSG_1064;Local - CIECAM 色度 -HISTORY_MSG_1065;Local - CIECAM 明度 J -HISTORY_MSG_1066;Local - CIECAM 明るさ Q -HISTORY_MSG_1067;Local - CIECAM コントラスト J -HISTORY_MSG_1068;Local - CIECAM しきい値 -HISTORY_MSG_1069;Local - CIECAM コントラスト Q -HISTORY_MSG_1070;Local - CIECAM 鮮やかさ -HISTORY_MSG_1071;Local - CIECAM 絶対輝度 -HISTORY_MSG_1072;Local - CIECAM 平均輝度 -HISTORY_MSG_1073;Local - CIECAM Cat16 -HISTORY_MSG_1074;Local - CIECAM ローカルコントラスト -HISTORY_MSG_1075;Local - CIECAM 観視条件 -HISTORY_MSG_1076;Local - CIECAM スロープ -HISTORY_MSG_1077;Local - CIECAM モード -HISTORY_MSG_1078;Local - レッドと肌色トーンを保護 -HISTORY_MSG_1079;Local - CIECAM シグモイドの強さ J -HISTORY_MSG_1080;Local - CIECAM シグモイドのしきい値 -HISTORY_MSG_1081;Local - CIECAM シグモイドのブレンド -HISTORY_MSG_1082;Local - CIECAM シグモイド Q ブラックEv ホワイトEv -HISTORY_MSG_1083;Local - CIECAM 色相 -HISTORY_MSG_1084;Local - ブラックEvとホワイトEvを使う -HISTORY_MSG_1085;Local - Jz 明度 -HISTORY_MSG_1086;Local - Jz コントラスト -HISTORY_MSG_1087;Local - Jz 色度 -HISTORY_MSG_1088;Local - Jz 色相 -HISTORY_MSG_1089;Local - Jz シグモイドの強さ -HISTORY_MSG_1090;Local - Jz シグモイドのしきい値 -HISTORY_MSG_1091;Local - Jz シグモイドのブレンド -HISTORY_MSG_1092;Local - Jz 順応 -HISTORY_MSG_1093;Local - CAMのモデル -HISTORY_MSG_1094;Local - Jz ハイライト -HISTORY_MSG_1095;Local - Jz ハイライトのしきい値 -HISTORY_MSG_1096;Local - Jz シャドウ -HISTORY_MSG_1097;Local - Jz シャドウのしきい値 -HISTORY_MSG_1098;Local - Jz SHの半径 -HISTORY_MSG_1099;Local - Cz(Hz)カーブ -HISTORY_MSG_1100;Local - 100カンデラのJzの参考値 -HISTORY_MSG_1101;Local - Jz PQ 再配分 -HISTORY_MSG_1102;Local - Jz(Hz)カーブ -HISTORY_MSG_1103;Local - 自然な彩度 ガンマ -HISTORY_MSG_1104;Local - シャープネス ガンマ -HISTORY_MSG_1105;Local - CIECAM トーン調整の方法 -HISTORY_MSG_1106;Local - CIECAM トーンカーブ -HISTORY_MSG_1107;Local - CIECAM 色調整の方法 -HISTORY_MSG_1108;Local - CIECAM カラーカーブ -HISTORY_MSG_1109;Local - Jz(Jz)カーブ -HISTORY_MSG_1110;Local - Cz(Cz)カーブ -HISTORY_MSG_1111;Local - Cz(Jz)カーブ -HISTORY_MSG_1112;Local - 強制的なJz -HISTORY_MSG_1113;Local - HDR PQ -HISTORY_MSG_1114;Local - Cie マスク 有効 -HISTORY_MSG_1115;Local - Cie マスク Cカーブ -HISTORY_MSG_1116;Local - Cie マスク Lカーブ -HISTORY_MSG_1117;Local - Cie マスク Hカーブ -HISTORY_MSG_1118;Local - Cie マスク ブレンド -HISTORY_MSG_1119;Local - Cie マスク 半径 -HISTORY_MSG_1120;Local - Cie マスク 色度 -HISTORY_MSG_1121;Local - Cie マスク コントラストカーブ -HISTORY_MSG_1122;Local - Cie マスク 復元のしきい値 -HISTORY_MSG_1123;Local - Cie マスク 復元 暗い部分 -HISTORY_MSG_1124;Local - Cie マスク 復元 明るい部分 -HISTORY_MSG_1125;Local - Cie マスク 復元の減衰 -HISTORY_MSG_1126;Local - Cie マスク ラプラシアン -HISTORY_MSG_1127;Local - Cie マスク ガンマ -HISTORY_MSG_1128;Local - Cie マスク スロープ -HISTORY_MSG_1129;Local - Cie 相対輝度 -HISTORY_MSG_1130;Local - Cie 彩度 Jz -HISTORY_MSG_1131;Local - マスク 色ノイズ除去  -HISTORY_MSG_1132;Local - Cie ウェーブレット シグマ Jz -HISTORY_MSG_1133;Local - Cie ウェーブレット レベル Jz -HISTORY_MSG_1134;Local - Cie ウェーブレット ローカルコントラスト Jz -HISTORY_MSG_1135;Local - Cie ウェーブレット 明瞭 Jz -HISTORY_MSG_1136;Local - Cie ウェーブレット 明瞭 Cz -HISTORY_MSG_1137;Local - Cie ウェーブレット 明瞭 ソフト -HISTORY_MSG_1138;Local - ローカル - Hz(Hz)カーブ -HISTORY_MSG_1139;Local - Jz ソフト Hカーブ -HISTORY_MSG_1140;Local - Jz 色度のしきい値 -HISTORY_MSG_1141;Local - 色度のカーブ Jz(Hz) -HISTORY_MSG_1142;Local - 強さ ソフト -HISTORY_MSG_1143;Local - Jz ブラックEv -HISTORY_MSG_1144;Local - Jz ホワイトEv -HISTORY_MSG_1145;Local - Jz 対数符号化 -HISTORY_MSG_1146;Local - Jz 対数符号化 目標のグレー -HISTORY_MSG_1147;Local - Jz ブラックEv ホワイトEv -HISTORY_MSG_1148;Local - Jz シグモイド -HISTORY_MSG_1149;Local - Q シグモイド -HISTORY_MSG_1150;Local - シグモイドQの代わりに対数符号化Qを使う +HISTORY_MSG_1051;ローカル - 残差画像 ウェーブレット ガンマ +HISTORY_MSG_1052;ローカル - 残差画像 ウェーブレット スロープ +HISTORY_MSG_1053;ローカル - ノイズ除去 ガンマ +HISTORY_MSG_1054;ローカル - ウェーブレット ガンマ +HISTORY_MSG_1055;ローカル - 色と明るさ ガンマ +HISTORY_MSG_1056;ローカル - ダイナミックレンジ圧縮と露光補正 ガンマ +HISTORY_MSG_1057;ローカル - CIECAM 有効 +HISTORY_MSG_1058;ローカル - CIECAM 全体的な強さ +HISTORY_MSG_1059;ローカル - CIECAM 自動グレー +HISTORY_MSG_1060;ローカル - CIECAM 元画像のの平均輝度 +HISTORY_MSG_1061;ローカル - CIECAM 元画像の絶対輝度 +HISTORY_MSG_1062;ローカル - CIECAM 元画像の周囲環境 +HISTORY_MSG_1063;ローカル - CIECAM 彩度 +HISTORY_MSG_1064;ローカル - CIECAM 色度 +HISTORY_MSG_1065;ローカル - CIECAM 明度 J +HISTORY_MSG_1066;ローカル - CIECAM 明るさ Q +HISTORY_MSG_1067;ローカル - CIECAM コントラスト J +HISTORY_MSG_1068;ローカル - CIECAM しきい値 +HISTORY_MSG_1069;ローカル - CIECAM コントラスト Q +HISTORY_MSG_1070;ローカル - CIECAM 鮮やかさ +HISTORY_MSG_1071;ローカル - CIECAM 絶対輝度 +HISTORY_MSG_1072;ローカル - CIECAM 平均輝度 +HISTORY_MSG_1073;ローカル - CIECAM Cat16 +HISTORY_MSG_1074;ローカル - CIECAM ローカルコントラスト +HISTORY_MSG_1075;ローカル - CIECAM 観視条件 +HISTORY_MSG_1076;ローカル - CIECAM スロープ +HISTORY_MSG_1077;ローカル - CIECAM モード +HISTORY_MSG_1078;ローカル - レッドと肌色トーンを保護 +HISTORY_MSG_1079;ローカル - CIECAM シグモイドの強さ J +HISTORY_MSG_1080;ローカル - CIECAM シグモイドのしきい値 +HISTORY_MSG_1081;ローカル - CIECAM シグモイドのブレンド +HISTORY_MSG_1082;ローカル - CIECAM シグモイド Q ブラックEv ホワイトEv +HISTORY_MSG_1083;ローカル - CIECAM 色相 +HISTORY_MSG_1084;ローカル - ブラックEvとホワイトEvを使う +HISTORY_MSG_1085;ローカル - Jz 明度 +HISTORY_MSG_1086;ローカル - Jz コントラスト +HISTORY_MSG_1087;ローカル - Jz 色度 +HISTORY_MSG_1088;ローカル - Jz 色相 +HISTORY_MSG_1089;ローカル - Jz シグモイドの強さ +HISTORY_MSG_1090;ローカル - Jz シグモイドのしきい値 +HISTORY_MSG_1091;ローカル - Jz シグモイドのブレンド +HISTORY_MSG_1092;ローカル - Jz 順応 +HISTORY_MSG_1093;ローカル - CAMのモデル +HISTORY_MSG_1094;ローカル - Jz ハイライト +HISTORY_MSG_1095;ローカル - Jz ハイライトのしきい値 +HISTORY_MSG_1096;ローカル - Jz シャドウ +HISTORY_MSG_1097;ローカル - Jz シャドウのしきい値 +HISTORY_MSG_1098;ローカル - Jz SHの半径 +HISTORY_MSG_1099;ローカル - Cz(Hz)カーブ +HISTORY_MSG_1100;ローカル - 100カンデラのJzの基準値 +HISTORY_MSG_1101;ローカル - Jz PQ 再配分 +HISTORY_MSG_1102;ローカル - Jz(Hz)カーブ +HISTORY_MSG_1103;ローカル - 自然な彩度 ガンマ +HISTORY_MSG_1104;ローカル - シャープネス ガンマ +HISTORY_MSG_1105;ローカル - CIECAM トーン調整の方法 +HISTORY_MSG_1106;ローカル - CIECAM トーンカーブ +HISTORY_MSG_1107;ローカル - CIECAM 色調整の方法 +HISTORY_MSG_1108;ローカル - CIECAM カラーカーブ +HISTORY_MSG_1109;ローカル - Jz(Jz)カーブ +HISTORY_MSG_1110;ローカル - Cz(Cz)カーブ +HISTORY_MSG_1111;ローカル - Cz(Jz)カーブ +HISTORY_MSG_1112;ローカル - 強制的なJz +HISTORY_MSG_1113;ローカル - HDR PQ +HISTORY_MSG_1114;ローカル - Cie マスク 有効 +HISTORY_MSG_1115;ローカル - Cie マスク Cカーブ +HISTORY_MSG_1116;ローカル - Cie マスク Lカーブ +HISTORY_MSG_1117;ローカル - Cie マスク Hカーブ +HISTORY_MSG_1118;ローカル - Cie マスク ブレンド +HISTORY_MSG_1119;ローカル - Cie マスク 半径 +HISTORY_MSG_1120;ローカル - Cie マスク 色度 +HISTORY_MSG_1121;ローカル - Cie マスク コントラストカーブ +HISTORY_MSG_1122;ローカル - Cie マスク 復元のしきい値 +HISTORY_MSG_1123;ローカル - Cie マスク 復元 暗い部分 +HISTORY_MSG_1124;ローカル - Cie マスク 復元 明るい部分 +HISTORY_MSG_1125;ローカル - Cie マスク 復元の減衰 +HISTORY_MSG_1126;ローカル - Cie マスク ラプラシアン +HISTORY_MSG_1127;ローカル - Cie マスク ガンマ +HISTORY_MSG_1128;ローカル - Cie マスク スロープ +HISTORY_MSG_1129;ローカル - Cie 相対輝度 +HISTORY_MSG_1130;ローカル - Cie 彩度 Jz +HISTORY_MSG_1131;ローカル - マスク 色ノイズ除去  +HISTORY_MSG_1132;ローカル - Cie ウェーブレット シグマ Jz +HISTORY_MSG_1133;ローカル - Cie ウェーブレット レベル Jz +HISTORY_MSG_1134;ローカル - Cie ウェーブレット ローカルコントラスト Jz +HISTORY_MSG_1135;ローカル - Cie ウェーブレット 明瞭 Jz +HISTORY_MSG_1136;ローカル - Cie ウェーブレット 明瞭 Cz +HISTORY_MSG_1137;ローカル - Cie ウェーブレット 明瞭 ソフト +HISTORY_MSG_1138;ローカル - ローカル - Hz(Hz)カーブ +HISTORY_MSG_1139;ローカル - Jz ソフト Hカーブ +HISTORY_MSG_1140;ローカル - Jz 色度のしきい値 +HISTORY_MSG_1141;ローカル - 色度のカーブ Jz(Hz) +HISTORY_MSG_1142;ローカル - 強さ ソフト +HISTORY_MSG_1143;ローカル - Jz ブラックEv +HISTORY_MSG_1144;ローカル - Jz ホワイトEv +HISTORY_MSG_1145;ローカル - Jz 対数符号化 +HISTORY_MSG_1146;ローカル - Jz 対数符号化 目標のグレー +HISTORY_MSG_1147;ローカル - Jz ブラックEv ホワイトEv +HISTORY_MSG_1148;ローカル - Jz シグモイド +HISTORY_MSG_1149;ローカル - Q シグモイド +HISTORY_MSG_1150;ローカル - シグモイドQの代わりに対数符号化Qを使う HISTORY_MSG_BLSHAPE;レベルによるぼかし HISTORY_MSG_BLURCWAV;色度のぼかし HISTORY_MSG_BLURWAV;輝度のぼかし HISTORY_MSG_BLUWAV;減衰応答 -HISTORY_MSG_CATCAT;モード Cat02/16 -HISTORY_MSG_CATCOMPLEX;色の見えモデルの機能水準 -HISTORY_MSG_CATMODEL;色の見えモデルのバージョン +HISTORY_MSG_CATCAT;CAL - モードの設定 +HISTORY_MSG_CATCOMPLEX;CAL - 機能水準の設定 +HISTORY_MSG_CATMODEL;CAL - 色の見えモデルの設定 HISTORY_MSG_CLAMPOOG;色域外の色を切り取る HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - 色の補正 HISTORY_MSG_COLORTONING_LABREGION_AB;CT - 色の補正 @@ -1422,7 +1411,7 @@ HISTORY_MSG_HISTMATCHING;トーンカーブの自動調節 HISTORY_MSG_HLBL;Color 色の波及 - ぼかし HISTORY_MSG_ICL_LABGRIDCIEXY;Cie xy HISTORY_MSG_ICM_AINTENT;アブストラクトプロファイルの意図 -HISTORY_MSG_ICM_BLUX;原色 ブルー X +HISTORY_MSG_ICM_BLUX;原色 ブルー X HISTORY_MSG_ICM_BLUY;原色 ブルー Y HISTORY_MSG_ICM_FBW;白黒 HISTORY_MSG_ICM_GREX;原色 グリーン X @@ -1462,7 +1451,7 @@ HISTORY_MSG_PERSP_PROJ_ANGLE;パースペクティブ - 回復 HISTORY_MSG_PERSP_PROJ_ROTATE;パースペクティブ - PCA 回転 HISTORY_MSG_PERSP_PROJ_SHIFT;パースペクティブ - PCA HISTORY_MSG_PIXELSHIFT_AVERAGE;PS - 平均 -HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - ブレに対するデモザイクの方式 +HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - 動体に対するデモザイクの方式 HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;ラインノイズフィルタの方向 HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAFラインフィルタ HISTORY_MSG_PREPROCWB_MODE;ホワイトバランスモードの前処理 @@ -1486,7 +1475,7 @@ HISTORY_MSG_SOFTLIGHT_ENABLED;ソフトライト HISTORY_MSG_SOFTLIGHT_STRENGTH;ソフトライト - 強さ HISTORY_MSG_SPOT;スポット除去 HISTORY_MSG_SPOT_ENTRY;スポット除去 - ポイント変更 -HISTORY_MSG_TEMPOUT;CAM02 自動色温度設定 +HISTORY_MSG_TEMPOUT;CAM02/16 自動色温度設定 HISTORY_MSG_THRESWAV;バランスのしきい値 HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - アンカー HISTORY_MSG_TRANS_METHOD;ジオメトリ - 方式 @@ -1512,7 +1501,7 @@ HISTORY_MSG_WAVLIMDEN;相互作用 レベル5~6 とレベル1~4 HISTORY_MSG_WAVLOWTHR;最小コントラストのしきい値 HISTORY_MSG_WAVMERGEC;色度の融合 HISTORY_MSG_WAVMERGEL;輝度の融合 -HISTORY_MSG_WAVMIXMET;ローカルコントラストの参考値 +HISTORY_MSG_WAVMIXMET;ローカルコントラストの基準値 HISTORY_MSG_WAVOFFSET;オフセット HISTORY_MSG_WAVOLDSH;古いアルゴリズムを使う HISTORY_MSG_WAVQUAMET;ノイズ除去モード @@ -1574,7 +1563,7 @@ ICCPROFCREATOR_PROF_V2;ICC v2 ICCPROFCREATOR_PROF_V4;ICC v4 ICCPROFCREATOR_SAVEDIALOG_TITLE;...でICCプロファイルを保存 ICCPROFCREATOR_SLOPE;勾配 -ICCPROFCREATOR_TRC_PRESET;トーンレスポンスカーブ +ICCPROFCREATOR_TRC_PRESET;トーンリプレーススカーブ INSPECTOR_WINDOW_TITLE;カメラ出し画像 IPTCPANEL_CATEGORY;カテゴリ IPTCPANEL_CATEGORYHINT;画像の意図 @@ -1792,7 +1781,7 @@ PARTIALPASTE_SHARPENEDGE;エッジ PARTIALPASTE_SHARPENING;シャープニング (USM/RL) PARTIALPASTE_SHARPENMICRO;マイクロコントラスト PARTIALPASTE_SOFTLIGHT;ソフトライト -PARTIALPASTE_SPOT;染み除去 +PARTIALPASTE_SPOT;スポット除去 PARTIALPASTE_TM_FATTAL;ダイナミックレンジ圧縮 PARTIALPASTE_VIBRANCE;自然な彩度 PARTIALPASTE_VIGNETTING;周辺光量補正 @@ -1828,7 +1817,7 @@ PREFERENCES_CHUNKSIZE_RAW_CA;Raw 色収差補正 PREFERENCES_CHUNKSIZE_RAW_RCD;RCD デモザイク PREFERENCES_CHUNKSIZE_RAW_XT;Xtrans デモザイク PREFERENCES_CHUNKSIZE_RGB;RGB 処理 -PREFERENCES_CIE;Ciecam +PREFERENCES_CIE;色の見えモデル PREFERENCES_CIEARTIF;アーティファクトを回避 PREFERENCES_CLIPPINGIND;クリッピング警告の表示 PREFERENCES_CLUTSCACHE;HaldCLUT cache @@ -2068,6 +2057,12 @@ SAVEDLG_WARNFILENAME;ファイルに名前が付けられます SHCSELECTOR_TOOLTIP;この3つのスライダーの位置をリセットするには\nマウスの右ボタンをクリック SOFTPROOF_GAMUTCHECK_TOOLTIP;有効にすると、出力プロファイルの色域から外れた色のピクセルをグレーで表示します SOFTPROOF_TOOLTIP;ソフトプルーフィング\n有効にすると、ICMツールの出力プロファイルを使った疑似的なレンダリングを行います。印刷した場合などの画像の印象を掴むのに大変便利です。 +TC_PRIM_BLUX;Bx +TC_PRIM_BLUY;By +TC_PRIM_GREX;Gx +TC_PRIM_GREY;Gy +TC_PRIM_REDX;Rx +TC_PRIM_REDY;Ry THRESHOLDSELECTOR_B;下 THRESHOLDSELECTOR_BL;下-左 THRESHOLDSELECTOR_BR;下-右 @@ -2169,7 +2164,7 @@ TP_COLORAPP_BRIGHT_TOOLTIP;CIECAM02/16の明るさは 色刺激から発せら TP_COLORAPP_CAT02ADAPTATION_TOOLTIP;設定を手動で行う場合、65以上の設定値を推奨 TP_COLORAPP_CATCLASSIC;クラシック TP_COLORAPP_CATMET_TOOLTIP;クラシック - 従来のCIECAMの作用です。色順応変換が、基本的な光源をベースにした'場面条件'と、基本的な光源をベースにした'観視条件'に対し、別々に作用します。\n\nシンメトリック – 色順応がホワイトバランスをベースにして作用します。'場面条件'、'画像の調整'、'観視条件'の設定はニュートラルになります。\n\n混成 – 作用は'クラシック'と同じですが、色順応はホワイトバランスをベースにします。 -TP_COLORAPP_CATMOD;モード Cat02/16 +TP_COLORAPP_CATMOD;モード TP_COLORAPP_CATSYMGEN;自動シンメトリック TP_COLORAPP_CATSYMSPE;混成 TP_COLORAPP_CHROMA;色度 (C) @@ -2177,7 +2172,7 @@ TP_COLORAPP_CHROMA_M;鮮やかさ (M) TP_COLORAPP_CHROMA_M_TOOLTIP;CIECAM02/16の鮮やかさは、グレーと比較して知覚される色の量のことで、その色刺激の映り方に彩が多いか少ないかを意味します。 TP_COLORAPP_CHROMA_S;彩度 (S) TP_COLORAPP_CHROMA_S_TOOLTIP;CIECAM02/16の彩度は、色刺激自体が持つ明るさと比較したその色合いに該当するもので、L*a*b*やRGBの彩度とは異なります。 -TP_COLORAPP_CHROMA_TOOLTIP;CIECAM02の色度は、同一の観視環境の下では白に見える色刺激と比較した、その色刺激の'色合い'に相当するもので、L*a*b*やRGBの色度とは異なります。 +TP_COLORAPP_CHROMA_TOOLTIP;CIECAM02/16の色度は、同一の観視環境の下では白に見える色刺激と比較した、その色刺激の'色合い'に相当するもので、L*a*b*やRGBの色度とは異なります。 TP_COLORAPP_CIECAT_DEGREE;CAT02/16(色順応変換02/16) TP_COLORAPP_CONTRAST;コントラスト (J) TP_COLORAPP_CONTRAST_Q;コントラスト (Q) @@ -2188,9 +2183,9 @@ TP_COLORAPP_CURVEEDITOR1_TOOLTIP;CIECAM02/16調整前のL(L*a*b*)のヒス TP_COLORAPP_CURVEEDITOR2;トーンカーブ2 TP_COLORAPP_CURVEEDITOR2_TOOLTIP;最初のJ(J)カーブトーンカーブも同じ使い方です TP_COLORAPP_CURVEEDITOR3;カラーカーブ -TP_COLORAPP_CURVEEDITOR3_TOOLTIP;色度、彩度、鮮やかさのいずれかを調整します\n\nCIECAM02/16調整前の色度(L*a*b*)のヒストグラムを表示します\nチェックボックスの'カーブにCIECAM02出力のヒストグラム' が有効の場合、CIECAM02調整後のC,sまたはMのヒストグラムを表示します\n\nC, sとMは、メインのヒストグラム・パネルには表示されません\n最終出力は、メインのヒストグラム・パネルを参照してください +TP_COLORAPP_CURVEEDITOR3_TOOLTIP;色度、彩度、鮮やかさのいずれかを調整します\n\nCIECAM02/16調整前の色度(L*a*b*)のヒストグラムを表示します\nチェックボックスの'カーブにCIECAM02/16出力のヒストグラム' が有効の場合、CIECAM02/16調整後のC,sまたはMのヒストグラムを表示します\n\nC, sとMは、メインのヒストグラム・パネルには表示されません\n最終出力は、メインのヒストグラム・パネルを参照してください TP_COLORAPP_DATACIE;カーブでCIECAM02/16出力のヒストグラムを表示 -TP_COLORAPP_DATACIE_TOOLTIP;有効の場合、CIECAM02/16カーブのヒストグラムは、JかQ、CIECAM02調整後のCかs、またはMの値/範囲の近似値を表示します\nこの選択はメイン・ヒストグラムパネルには影響を与えません\n\n無効の場合、CIECAM02カーブのヒストグラムは、CIECAM調整前のL*a*b*値を表示します +TP_COLORAPP_DATACIE_TOOLTIP;有効の場合、CIECAM02/16カーブのヒストグラムは、JかQ、CIECAM02/16調整後のCかs、またはMの値/範囲の近似値を表示します\nこの選択はメイン・ヒストグラムパネルには影響を与えません\n\n無効の場合、CIECAM02/16カーブのヒストグラムは、CIECAM調整前のL*a*b*値を表示します TP_COLORAPP_DEGREE_TOOLTIP;CAT02/16は色順応変換の一つで、一定の光源(例えばD65)のホワイトポイントの値を、別な光源(例えばD50 やD55)のホワイトポイントの値に変換することです(WPモデルを参照)。 TP_COLORAPP_DEGREOUT_TOOLTIP;CAT02/16は色順応変換の一つで、一定の光源(例えばD50)のホワイトポイントの値を、別な光源(例えばD75)のホワイトポイントの値に変換することです(WPモデルを参照)。 TP_COLORAPP_FREE;任意の色温度と色偏差 + CAT02/16 + [出力] @@ -2209,30 +2204,30 @@ TP_COLORAPP_ILA;白熱灯標準A 2856K TP_COLORAPP_ILFREE;フリー TP_COLORAPP_ILLUM;光源 TP_COLORAPP_ILLUM_TOOLTIP;撮影条件に最も近い条件を選択します\n一般的にはD50 ですが、時間と緯度に応じて変えます -TP_COLORAPP_LABEL;色の見えモデル(CIECAM02/16) -TP_COLORAPP_LABEL_CAM02;画像の調整 +TP_COLORAPP_LABEL;色の見え&明るさ +TP_COLORAPP_LABEL_CAM02;画像編集 TP_COLORAPP_LABEL_SCENE;場面条件 TP_COLORAPP_LABEL_VIEWING;観視条件 TP_COLORAPP_LIGHT;明度 (J) -TP_COLORAPP_LIGHT_TOOLTIP;CIECAM02の明度は、同じような環視環境の下で白に見える色刺激の明瞭度と、その色の明瞭度を比較したもので、L*a*b*やRGBの明度とは異なります。 +TP_COLORAPP_LIGHT_TOOLTIP;CIECAM02/16の明度は、同じような環視環境の下で白に見える色刺激の明瞭度と、その色の明瞭度を比較したもので、L*a*b*やRGBの明度とは異なります。 TP_COLORAPP_MEANLUMINANCE;平均輝度 (Yb%) -TP_COLORAPP_MOD02;CIECAM02 -TP_COLORAPP_MOD16;CIECAM16 +TP_COLORAPP_MOD02;CAM02 +TP_COLORAPP_MOD16;CAM16 TP_COLORAPP_MODEL;ホワイトポイント・モデル TP_COLORAPP_MODELCAT;色の見えモデル -TP_COLORAPP_MODELCAT_TOOLTIP;色の見えモデルはCIECAM02或いはCIECAM16のどちらかを選択出来ます\n CIECAM02の方がより正確な場合があります\n CIECAM16の方がアーティファクトの発生が少ないでしょう +TP_COLORAPP_MODELCAT_TOOLTIP;色の見えモデルはCAM02或いはCAM16のどちらかを選択出来ます\n CAM02の方がより正確な場合があります\n CAM16の方がアーティファクトの発生が少ないでしょう TP_COLORAPP_MODEL_TOOLTIP;ホワイトポイントモデル\n\nWB [RT] + [出力]\:周囲環境のホワイトバランスは、カラータブのホワイトバランスが使われます。CIECAM02/16の光源にはD50が使われ, 出力デバイスのホワイトバランスには観視環境のホワイトバランスが使われます\n\nWB [RT+CAT02] + [出力]:カラータブのホワイトバランスがCAT02で使われます。出力デバイスのホワイトバランスには観視環境のホワイトバランスが使われます\n\n任意の色温度と色偏差 + CAT02 + [出力]:色温度と色偏差はユーザーが設定します。出力デバイスのホワイトバランスには観視環境のホワイトバランスが使われます TP_COLORAPP_NEUTRAL;リセット TP_COLORAPP_NEUTRAL_TOOLTIP;全てのスライダーチェックボックスとカーブをデフォルトにリセットします TP_COLORAPP_RSTPRO;レッドと肌色トーンを保護 TP_COLORAPP_RSTPRO_TOOLTIP;レッドと肌色トーンを保護はスライダーとカーブの両方に影響します -TP_COLORAPP_SOURCEF_TOOLTIP;撮影条件に合わせて、その条件とデータを通常の範囲に収めます。ここで言う“通常”とは、平均的或いは標準的な条件とデータのことです。例えば、CIECAM02の補正を計算に入れずに収める。 +TP_COLORAPP_SOURCEF_TOOLTIP;撮影条件に合わせて、その条件とデータを通常の範囲に収めます。ここで言う“通常”とは、平均的或いは標準的な条件とデータのことです。例えば、CIECAM02/16の補正を計算に入れずに収める。 TP_COLORAPP_SURROUND;観視時の周囲環境 TP_COLORAPP_SURROUNDSRC;撮影時の周囲環境 TP_COLORAPP_SURROUND_AVER;平均 TP_COLORAPP_SURROUND_DARK;暗い TP_COLORAPP_SURROUND_DIM;薄暗い -TP_COLORAPP_SURROUND_EXDARK;非常に暗い +TP_COLORAPP_SURROUND_EXDARK;非常に暗い TP_COLORAPP_SURROUND_TOOLTIP;出力デバイスで観視する時の周囲環境を考慮するため、画像の明暗と色を変えます\n\n平均:\n周囲が平均的な明るさ(標準)\n画像は変わりません\n\n薄暗い:\n薄暗い環境、例、TVを見る環境\n画像は若干暗くなります\n\n暗い:\n暗い環境 例、プロジェクターを見る環境\n画像はかなり暗くなります\n\n非常に暗い:\n非常に暗い環境 (例、カットシートを使っている)\n画像はとても暗くなります TP_COLORAPP_SURSOURCE_TOOLTIP;撮影時の周囲環境を考慮するため、画像の明暗と色を変えます。\n平均:周囲が平均的な明るさ(標準)。画像は変化しません。\n\n薄暗い:画像が少し明るくなります。\n\n暗い:画像が更に明るくなります。\n\n非常に暗い:画像は非常に明るくなります。 TP_COLORAPP_TCMODE_BRIGHTNESS;明るさ @@ -2532,8 +2527,8 @@ TP_ICM_NEUTRAL;リセット TP_ICM_NOICM;No ICM: sRGB 出力 TP_ICM_OUTPUTPROFILE;出力プロファイル TP_ICM_OUTPUTPROFILE_TOOLTIP;デフォルトでは、全てのRTv4或いはRTv2プロファイルでTRC - sRGB: ガンマ=2.4 勾配=12.92が適用されています\n\n'ICCプロファイルクリエーター'でv4或いはv2のプロファイルを以下の条件で作成出来ます;\n 原色: Aces AP0, Aces AP1, AdobeRGB, Prophoto, Rec2020, sRGB, Widegamut, BestRGB, BetaRGB, BruceRGB, Custom\n TRC: BT709, sRGB, 線形, 標準ガンマ=2.2, 標準ガンマ=1.8, カスタム\n 光源: D41, D50, D55, D60, D65, D80, stdA 2856K -TP_ICM_PRIMBLU_TOOLTIP;原色 ブルー:\nsRGB x=0.15 y=0.06\nAdobe x=0.15 y=0.06\nWidegamut x=0.157 y=0.018\nRec2020 x=0.131 y=0.046\nACES P1 x=0.128 y= 0.044\nACES P0 x=0.0001 y=-0.077\nProphoto x=0.0366 y=0.0001\nBruceRGB x=0.15 y=0.06\nBeta RGB x=0.1265 y=0.0352\nBestRGB x=0.131 y=0.046 -TP_ICM_PRIMGRE_TOOLTIP;原色 グリーン:\nsRGB x=0.3 y=0.6\nAdobe x=0.21 y=0.71\nWidegamut x=0.115 y=0.826\nRec2020 x=0.17 y=0.797\nACES P1 x=0.165 y= 0.83\nACES P0 x=0.0 y=1.0\nProphoto x=0.1596 y=0.8404\nBruceRGB x=0.28 y=0.65\nBeta RGB x=0.1986 y=0.7551\nBest RGB x=0.2150 0.7750 +TP_ICM_PRIMBLU_TOOLTIP;原色 ブルー:\nsRGB x=0.15 y=0.06\nAdobe x=0.15 y=0.06\nWidegamut x=0.157 y=0.018\nRec2020 x=0.131 y=0.046\nACES P1 x=0.128 y= 0.044\nACES P0 x=0.0001 y=-0.077\nProphoto x=0.0366 y=0.0001\nBruceRGB x=0.15 y=0.06\nBeta RGB x=0.1265 y=0.0352\nBestRGB x=0.131 y=0.046 +TP_ICM_PRIMGRE_TOOLTIP;原色 グリーン:\nsRGB x=0.3 y=0.6\nAdobe x=0.21 y=0.71\nWidegamut x=0.115 y=0.826\nRec2020 x=0.17 y=0.797\nACES P1 x=0.165 y= 0.83\nACES P0 x=0.0 y=1.0\nProphoto x=0.1596 y=0.8404\nBruceRGB x=0.28 y=0.65\nBeta RGB x=0.1986 y=0.7551\nBest RGB x=0.2150 0.7750 TP_ICM_PRIMILLUM_TOOLTIP;画像を元のモード(“作業プロファイル”)から異なるモード(“変換先の原色”)に変えることが出来ます。画像に対し異なるカラーモードを選択すると、画像の色値を恒久的に変えることになります。\n\n‘原色’の変更は非常に複雑で、その使い方は非常に難しいものです。熟達した経験が必要です。\nチャンネルミキサーの原色のように、エキゾチックな色の調整が可能です。\nカスタム(スライダー)を使ってカメラのキャリブレーションを変えることが出来ます。 TP_ICM_PRIMRED_TOOLTIP;原色 レッド:\nsRGB x=0.64 y=0.33\nAdobe x=0.64 y=0.33\nWidegamut x=0.735 y=0.265\nRec2020 x=0.708 y=0.292\nACES P1 x=0.713 y= 0.293\nACES P0 x=0.7347 y=0.2653\nProphoto x=0.7347 y=0.2653\nBruceRGB x=0.64 y=0.33\nBeta RGB x=0.688 y=0.3112\nBestRGB x=0.7347 y=0.2653 TP_ICM_PROFILEINTENT;レンダリングの意図 @@ -2669,8 +2664,8 @@ TP_LOCALLAB_BILATERAL;平滑化フィルタ TP_LOCALLAB_BLACK_EV;ブラックEv TP_LOCALLAB_BLCO;色度だけ TP_LOCALLAB_BLENDMASKCOL;ブレンド -TP_LOCALLAB_BLENDMASKMASK;輝度マスクを強める/弱める -TP_LOCALLAB_BLENDMASKMASKAB;色度マスクを強める/弱める +TP_LOCALLAB_BLENDMASKMASK;マスクの輝度の加減 +TP_LOCALLAB_BLENDMASKMASKAB;マスクの色度の加減 TP_LOCALLAB_BLENDMASKMASK_TOOLTIP;スライダーの値が0の場合は作用しません\n元画像にマスクを追加したり、追加したマスクを削除します TP_LOCALLAB_BLENDMASK_TOOLTIP;ブレンド=0の場合は、形状検出だけが改善します\nブレンドが0より大きい場合は、画像にマスクが追加されます。 ブレンドが0より小さい場合は、画像からマスクが除かれます。 TP_LOCALLAB_BLGUID;ガイド付きフィルタ @@ -2730,7 +2725,7 @@ TP_LOCALLAB_CIEC;色の見えモデルの環境変数を使う TP_LOCALLAB_CIECAMLOG_TOOLTIP;このモジュールはCIE色の見えモデルをベースにしています。このモデルは異なる光源の下で人の目が知覚する色を真似るものです。\n最初の処理は’場面条件’で対数符号化によって実行されます。この際、撮影時の’絶対輝度’が使われます。\n次の処理は単純化した’画像の調整’で3つに絞り込んだ変数(ローカルコントラスト、コントラストJ、彩度S)を使います。\n3つ目の処理は’観視条件’で出力画像を見る条件(モニター、TV、プロジェクター、プリンターなどのこと)を考慮します。この処理により表示媒体に関わらず同じ画像の色やコントラストを維持します。 TP_LOCALLAB_CIECOLORFRA;色 TP_LOCALLAB_CIECONTFRA;コントラスト -TP_LOCALLAB_CIELIGHTCONTFRA;明度とコントラスト +TP_LOCALLAB_CIELIGHTCONTFRA;明るさとコントラスト TP_LOCALLAB_CIELIGHTFRA;明度 TP_LOCALLAB_CIEMODE;処理過程の位置の変更 TP_LOCALLAB_CIEMODE_COM;デフォルト @@ -2741,7 +2736,7 @@ TP_LOCALLAB_CIEMODE_WAV;ウェーブレット TP_LOCALLAB_CIETOOLEXP;カーブ TP_LOCALLAB_CIE_TOOLNAME;色の見えモデル(CAM16とJzCzHz) TP_LOCALLAB_CIRCRADIUS;スポットの中心の大きさ -TP_LOCALLAB_CIRCRAD_TOOLTIP;この円内の情報がRT-スポットの編集の参考値となります。色相、輝度、色度、Sobelの形状検出に使います。\n小さい半径は花の色などの補正に。\n大きな半径は肌などの補正に適しています。 +TP_LOCALLAB_CIRCRAD_TOOLTIP;この円内の情報がRT-スポットの編集の基準値となります。色相、輝度、色度、Sobelの形状検出に使います。\n小さい半径は花の色などの補正に。\n大きな半径は肌などの補正に適しています。 TP_LOCALLAB_CLARICRES;色度を融合 TP_LOCALLAB_CLARIFRA;明瞭とシャープマスク/ブレンド & ソフトイメージ TP_LOCALLAB_CLARIJZ_TOOLTIP;レベル0から4まではシャープマスクが働きます\nレベル5以上では明瞭が働きます @@ -2799,11 +2794,11 @@ TP_LOCALLAB_DENOICHRODET_TOOLTIP;漸進的にフーリエ変換(離散コサ TP_LOCALLAB_DENOICHROF_TOOLTIP;小さいディテールの色ノイズを調整します TP_LOCALLAB_DENOIEQUALCHRO_TOOLTIP;ブルー/イエロー、或いはレッド/グリーンの補色次元で色ノイズを軽減します TP_LOCALLAB_DENOIEQUAL_TOOLTIP;シャドウ、或いはハイライト部分で、ある程度ノイズ低減を実行出来ます -TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;漸進的にフーリエ変換(離散コサイン変換)を適用することで、輝度のディテールを回復します +TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;漸進的にフーリエ変換(離散コサイン変換)を適用することで、輝度のディテールを回復します TP_LOCALLAB_DENOIMASK;色ノイズのマスク TP_LOCALLAB_DENOIMASK_TOOLTIP;全ての機能でマスクの色ノイズの程度を加減することが出来ます。\nLC(h)カーブを使う際、アーティファクトを避けたり、色度をコントロールするのに便利です。 TP_LOCALLAB_DENOIQUA_TOOLTIP;’控え目’なモードでは、低周波ノイズは除去されません。’積極的’なモードは低周波ノイズも除去します。\n’控え目’も’積極的’も、ウェーブレットとDCTを使いますが、’輝度のノンローカルミーン’を併用することも出来ます。 -TP_LOCALLAB_DENOITHR_TOOLTIP;均一及び低コントラスト部分のノイズを減らす補助としてエッジ検出を調整します +TP_LOCALLAB_DENOITHR_TOOLTIP;均一及び低コントラスト部分のノイズを減らす補助としてエッジ検出を調整します TP_LOCALLAB_DENOI_EXP;ノイズ除去 TP_LOCALLAB_DENOI_TOOLTIP;このモジュールは単独のノイズ低減機能(処理工程の最後の方に位置)として、或いはメインのディテールタブに付属するノイズ低減(処理工程の最初の方に位置)の追加機能として使うことが出来ます。\n色(ΔE)を基本に、スコープを使って作用に差を付けることが出来ます。\n但し、RT-スポットは最低128x128の大きさの必要です TP_LOCALLAB_DEPTH;深度 @@ -2844,7 +2839,7 @@ TP_LOCALLAB_EXPCHROMA_TOOLTIP;色が褪せるのを避けるため、’露光 TP_LOCALLAB_EXPCOLOR_TOOLTIP;色、明度、コントラストの調整に使います。赤目やセンサーの汚れに起因する不良の補正にも使えます。 TP_LOCALLAB_EXPCOMP;露光量補正 ƒ TP_LOCALLAB_EXPCOMPINV;露光量補正 -TP_LOCALLAB_EXPCOMP_TOOLTIP;ポートレート或いは色の階調が少ない画像の場合、’設定’の’形状検出’を調整します:\n\n’ΔEスコープのしきい値’を増やします\n’ΔEの減衰’を減らします\n’バランス ab-L(ΔE)'を増やします +TP_LOCALLAB_EXPCOMP_TOOLTIP;ポートレート或いは色の階調が少ない画像の場合、’設定’の’形状検出’を調整します:\n\n’ΔEスコープのしきい値’を増やします\n’ΔEの減衰’を減らします\n’バランス ab-L(ΔE)'を増やします TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP;RawPediaの'ウェーブレットのレベル’を参照して下さい。\nローカル編集のウェーブレットのレベルは異なる部分が幾つかあります:各ディテールのレベルに対する調整機能がより多く、多様性が増します。\n例、ウェーブレットのレベルのトーンマッピングです。 TP_LOCALLAB_EXPCONTRAST_TOOLTIP;あまりに小さいRT-スポットの設定は避けます(少なくとも32x32ピクセル以上)。\n低い’境界値’と高い’境界の減衰’値、及び’スコープ’値を使い、小さいRT-スポットを真似て欠陥部分を補正します。\nアーティファクトを軽減するために、必要に応じて’ソフトな半径’を調整して ’明瞭とシャープマスク’、’ファイルの融合’を使います。 TP_LOCALLAB_EXPCURV;カーブ @@ -2890,7 +2885,7 @@ TP_LOCALLAB_GAMW;ガンマ(ウェーブレットピラミッド) TP_LOCALLAB_GRADANG;階調フィルタの角度 TP_LOCALLAB_GRADANG_TOOLTIP;-180度から+180度の間で角度を調整 TP_LOCALLAB_GRADFRA;階調フィルタのマスク -TP_LOCALLAB_GRADGEN_TOOLTIP;階調フィルタの機能は’色と明るさ’と、’露光’、'シャドウ/ハイライト”、’自然な彩度’に備わっています\n\n自然な彩度、色と明るさには輝度、色調、色相の階調フィルタが使えます\nフェザー処理は設定の中にあります +TP_LOCALLAB_GRADGEN_TOOLTIP;階調フィルタの機能は’色と明るさ’と、’露光’、'シャドウ/ハイライト”、’自然な彩度’に備わっています\n\n自然な彩度、色と明るさには輝度、色調、色相の階調フィルタが使えます\nフェザー処理は設定の中にあります TP_LOCALLAB_GRADLOGFRA;輝度の階調フィルタ TP_LOCALLAB_GRADSTR;階調フィルタ 強さ TP_LOCALLAB_GRADSTRAB_TOOLTIP;色度の階調の強さを調整します @@ -2911,7 +2906,7 @@ TP_LOCALLAB_GUIDBL;ソフトな半径 TP_LOCALLAB_GUIDBL_TOOLTIP;半径を変えられるガイド付きフィルタを適用します。アーティファクトを軽減したり、画像にぼかしを掛けたり出来ます。 TP_LOCALLAB_GUIDEPSBL_TOOLTIP;ガイド付きフィルタの配分機能を変化させます。マイナス値の設定はガウスぼかしに似た効果となります TP_LOCALLAB_GUIDFILTER;ガイド付きフィルタの半径 -TP_LOCALLAB_GUIDFILTER_TOOLTIP;アーティファクトが減ったり、増えたりします +TP_LOCALLAB_GUIDFILTER_TOOLTIP;アーティファクトが減ったり、増えたりします TP_LOCALLAB_GUIDSTRBL_TOOLTIP;ガイド付きフィルタの強さ TP_LOCALLAB_HHMASK_TOOLTIP;例えば肌の微妙な色相調整に使います TP_LOCALLAB_HIGHMASKCOL;ハイライト @@ -2926,10 +2921,10 @@ TP_LOCALLAB_INVERS_TOOLTIP;インバースを選択すると使える機能の TP_LOCALLAB_INVMASK;インバースアルゴリズム TP_LOCALLAB_ISOGR;配分(ISO) TP_LOCALLAB_JAB;ブラックEvとホワイトEvを使う -TP_LOCALLAB_JABADAP_TOOLTIP;均一的知覚の順応\n"絶対輝度"を考慮したJzと彩度の関係を自動的に調整します -TP_LOCALLAB_JZ100;Jz reference 100カンデラでのJzの参考値 -TP_LOCALLAB_JZ100_TOOLTIP;100カンデラ毎平方メートルでのJzの参考値(画像シグナル)を自動で調整します。\n彩度の値と“PU 順応” (均一的な知覚の順応)が変わります。 -TP_LOCALLAB_JZADAP;均一的知覚の順応 +TP_LOCALLAB_JABADAP_TOOLTIP;PU(均一的知覚)の順応\n"絶対輝度"を考慮したJzと彩度の関係を自動的に調整します +TP_LOCALLAB_JZ100;Jzの基準値 100カンデラ +TP_LOCALLAB_JZ100_TOOLTIP;100カンデラ毎平方メートルでのJzの基準値(画像シグナル)を自動で調整します。\n彩度の値と“PU 順応” (均一的な知覚の順応)が変わります。 +TP_LOCALLAB_JZADAP;PU-順応 TP_LOCALLAB_JZCH;色度 TP_LOCALLAB_JZCHROM;色度 TP_LOCALLAB_JZCLARICRES;色度Czを融合 @@ -2942,14 +2937,14 @@ TP_LOCALLAB_JZHFRA;Hzカーブ TP_LOCALLAB_JZHJZFRA;Jz(Hz)カーブ TP_LOCALLAB_JZHUECIE;色相の回転 TP_LOCALLAB_JZLIGHT;明るさ -TP_LOCALLAB_JZLOG;Jz 対数符号化 +TP_LOCALLAB_JZLOG;対数符号化 Jz TP_LOCALLAB_JZLOGWBS_TOOLTIP;対数符号化を使うかシグモイドを使うかでブラックEvとホワイトEvの調整が異なる場合があります\nシグモイドの場合、ハイライト、コントラスト、彩度の良好なレンダリングを得るために、ホワイトEvの調整(多くの場合、増やす方向)が必要になることがあります TP_LOCALLAB_JZLOGWB_TOOLTIP;自動を有効にすると、スポット内のEvレベルと'平均輝度 Yb%'が計算されて調整されます。計算結果は"対数符号化 Jz"を含む、全てのJzの働きに使われます。\nまた、撮影時の絶対輝度が計算されます。 TP_LOCALLAB_JZLOGYBOUT_TOOLTIP;Ybは背景の平均輝度を指し、グレーの割合(%)で表します。グレー18%は背景のCIE Labの輝度値が50%であることと同じです。\nデータは画像の平均輝度に基づいています\n対数符号化が使われている場合は、対数符号化が行われる前に適用するゲインの量を決めるために平均輝度が使われます。平均輝度の値が低い程、ゲインが増えます。 TP_LOCALLAB_JZMODECAM_TOOLTIP;Jzが使えるのは機能水準が'高度'な場合だけです。Jzが機能するのは出力デバイス(モニター)がHDRの場合だけです(最大出力輝度が100カンデラ毎平方メートル以上、理想的には4000から10000カンデラ毎平方メートル、ブラックポイントが0.005カンデラ毎平方メートル以下のモニターです)。ここで想定されるのは、a)モニターのICCのプロファイル接続色空間でJzazbz (或いはXYZ)が使える、b)実数精度で作業出来る、c)モニターがキャリブレートされている(出来れば、DCI-P3、或いはRec-2020の色域で)、d) 通常のガンマ(sRGB、或いはBT709)が知覚量子化の関数で置き換えられる、ことです。 TP_LOCALLAB_JZPQFRA;Jz 再マッピング -TP_LOCALLAB_JZPQFRA_TOOLTIP;Jzのアルゴリズムを以下の様にSDR(標準ダイナミックレンジ)の環境、或いはHDR(ハイダイナミックレンジ)の環境の特性に対して適応させることが出来ます:\n a) 輝度値が0から100カンデラ毎平方メートルの間では、システムがSDRであるように作用する\n b) 輝度値が100から10000カンデラ毎平方メートルの間では、画像とモニターのHDR特性にJzのアルゴリズムを適応させる。\n\n“PQ - 最大輝度P”を10000カンデラ毎平方メートルに設定すると、“Jzの再マッピング”がJzazbzのオリジナルアルゴリズムの特性を示します。 -TP_LOCALLAB_JZPQREMAP;PQ - 最大輝度 +TP_LOCALLAB_JZPQFRA_TOOLTIP;Jzのアルゴリズムを以下の様にSDR(標準ダイナミックレンジ)の環境、或いはHDR(ハイダイナミックレンジ)の環境の特性に対して適応させることが出来ます:\n a) 輝度値が0から100カンデラ毎平方メートルの間では、システムがSDRであるように作用する\n b) 輝度値が100から10000カンデラ毎平方メートルの間では、画像とモニターのHDR特性にJzのアルゴリズムを適応させる。\n\n“PQ - 最大輝度P”を10000カンデラ毎平方メートルに設定すると、“Jzの再マッピング”がJzazbzのオリジナルアルゴリズムの特性を示します。 +TP_LOCALLAB_JZPQREMAP;PQ - 最大輝度 TP_LOCALLAB_JZPQREMAP_TOOLTIP;PQ (知覚量子化) - PQの内部関数を変えることが出来ます。デフォルトでは120カンデラ毎平方メートルが設定されていますが、一般的な10000カンデラ毎平方メートルに変えられます。\n異なる画像、処理、デバイスに適応させるために使います。 TP_LOCALLAB_JZQTOJ;相対輝度 TP_LOCALLAB_JZQTOJ_TOOLTIP;"絶対輝度"の代わりに"相対輝度"が使えるようになります - 明るさが明度で表現されるようになります。\n変更により、明るさとコントラストのスライダー、及びJz(Jz)カーブが影響を受けます。 @@ -2960,7 +2955,7 @@ TP_LOCALLAB_JZSTRSOFTCIE;ガイド付きフィルタの強さ TP_LOCALLAB_JZTARGET_EV;観視の平均輝度(Yb%) TP_LOCALLAB_JZTHRHCIE;Jz(Hz)の色度のしきい値 TP_LOCALLAB_JZWAVEXP;Jz ウェーブレット -TP_LOCALLAB_LABBLURM;ぼかしマスク +TP_LOCALLAB_LABBLURM;マスクのぼかし TP_LOCALLAB_LABEL;ローカル編集 TP_LOCALLAB_LABGRID;カラー補正グリッド TP_LOCALLAB_LABGRIDMERG;背景 @@ -2999,6 +2994,7 @@ TP_LOCALLAB_LOG;対数符号化 TP_LOCALLAB_LOG1FRA;CAM16による画像の調整 TP_LOCALLAB_LOG2FRA;観視条件 TP_LOCALLAB_LOGAUTO;自動 +TP_LOCALLAB_LOGAUTOGRAYJZ_TOOLTIP;場面条件の’平均輝度’を自動で計算します。 TP_LOCALLAB_LOGAUTOGRAY_TOOLTIP;相対的な露光レベルの中の’自動’ボタンを押すと、撮影画像の環境に関する平均輝度が自動的に計算されます。 TP_LOCALLAB_LOGAUTO_TOOLTIP;'自動平均輝度(Yb%)'のオプションが有効になっている時に、このボタンを押すと撮影画像の環境に関する’ダイナミックレンジ’と’平均輝度’が計算されます。\nまた、撮影時の絶対輝度も計算されます。\n再度ボタンを押すと自動的にこれら値が調整されます。 TP_LOCALLAB_LOGBASE_TOOLTIP;デフォルト値は2です\n2以下ではアルゴリズムの働きが弱まり、シャドウ部分が暗く、ハイライト部分が明るくなります\n2より大きい場合は、シャドウ部分が濃いグレーに変わり、ハイライト部分は白っぽくなります @@ -3020,9 +3016,9 @@ TP_LOCALLAB_LOGFRA;場面条件 TP_LOCALLAB_LOGFRAME_TOOLTIP;RT-スポットに関する露出のレベルと’平均輝度 Yb%'(グレーポイントの情報源)を計算し調整します。結果は全てのLab関連処理と殆どのRGB関連処理に使われます。\nまた、場面の絶対輝度も考慮します。 TP_LOCALLAB_LOGIMAGE_TOOLTIP;対応する色の見えモデルの変数(例えば、コントラストJと彩度S、及び機能水準が高度な場合の、コントラストQ、明るさQ、明度J、鮮やかさM)を考慮します。 TP_LOCALLAB_LOGLIGHTL;明度 (J) -TP_LOCALLAB_LOGLIGHTL_TOOLTIP;L*a*b*の明度に近いものですが、知覚される彩色の増加を考慮ています。 +TP_LOCALLAB_LOGLIGHTL_TOOLTIP;L*a*b*の明度に近いものですが、知覚される彩色の増加を考慮ています。 TP_LOCALLAB_LOGLIGHTQ;明るさ (Q) -TP_LOCALLAB_LOGLIGHTQ_TOOLTIP;その色刺激から発せられる知覚された光の量を意味します。\nその色刺激の明るさの多寡の指標です。 +TP_LOCALLAB_LOGLIGHTQ_TOOLTIP;その色刺激から発せられる知覚された光の量を意味します。\nその色刺激の明るさの多寡の指標です。 TP_LOCALLAB_LOGLIN;対数モード TP_LOCALLAB_LOGPFRA;相対的な露光レベル TP_LOCALLAB_LOGREPART;全体の強さ @@ -3034,7 +3030,7 @@ TP_LOCALLAB_LOGVIEWING_TOOLTIP;最終画像を見る周囲環境同様、それ TP_LOCALLAB_LOG_TOOLNAME;対数符号化 TP_LOCALLAB_LUM;LL - CC TP_LOCALLAB_LUMADARKEST;最も暗い部分 -TP_LOCALLAB_LUMASK;背景の色/輝度のマスク +TP_LOCALLAB_LUMASK;マスクの背景色と輝度 TP_LOCALLAB_LUMASK_TOOLTIP;マスクの表示(マスクと修正領域)で、背景のグレーを調節します TP_LOCALLAB_LUMAWHITESEST;最も明るい部分 TP_LOCALLAB_LUMFRA;L*a*b* 標準 @@ -3094,8 +3090,7 @@ TP_LOCALLAB_MASKRESVIB_TOOLTIP;'マスクと修正領域'のL(L)やLC(H)マス TP_LOCALLAB_MASKRESWAV_TOOLTIP;'マスクと修正領域'のL(L)やLC(H)マスクに内包されている輝度の情報をベースに、”ローカルコントラスト ウェーブレット”の設定による効果を和らげるために使います。\n この機能を使うためにはL(L)やLC(H)のマスクを有効にする必要があります。\n 暗いしきい値以下と明るいしきい値以上の'暗い'領域と'明るい'領域は、'ローカルコントラスト ウェーブレット'の設定によって変更される前の値(元の値)に漸進的に復元されます。\n 2つのしきい値の間の部分では、'ローカルコントラスト ウェーブレット'の設定値が100%適用されます。 TP_LOCALLAB_MASKUNUSABLE;'マスクと修正領域'のマスクが無効 TP_LOCALLAB_MASKUSABLE;'マスクと修正領域'のマスクが有効 -TP_LOCALLAB_MASK_TOOLTIP;一つの機能の中で複数のマスクを活用することが出来ます。他の機能を有効にしてそのマスクだけを使います(機能の中のスライダー値は全て0にする)。\n\nまたは、RT-スポットを複製し、初めのスポットの近くに置き、そのRT-スポットのマスクを使います。この場合、調整のための参考値の違いが小さいため、より精緻な調整が可能です。 -TP_LOCALLAB_MED;中間 +TP_LOCALLAB_MASK_TOOLTIP;一つの機能の中で複数のマスクを活用することが出来ます。他の機能を有効にしてそのマスクだけを使います(機能の中のスライダー値は全て0にする)。\n\nまたは、RT-スポットを複製し、初めのスポットの近くに置き、そのRT-スポットのマスクを使います。この場合、調整のための基準値の違いが小さいため、より精緻な調整が可能です。 TP_LOCALLAB_MEDIAN;メディアン 低 TP_LOCALLAB_MEDIANITER_TOOLTIP;メディアンフィルタ適用の繰り返し回数を設定します TP_LOCALLAB_MEDIAN_TOOLTIP;メディアンの値を3x3~9x9ピクセルの範囲で選べます。値を高くするほどノイズ低減とぼかしが強くなります @@ -3138,7 +3133,7 @@ TP_LOCALLAB_MRFIV;背景 TP_LOCALLAB_MRFOU;前のRT-スポット TP_LOCALLAB_MRONE;なし TP_LOCALLAB_MRTHR;オリジナルRT-スポット -TP_LOCALLAB_MULTIPL_TOOLTIP;トーンの幅が広い画像、-18EV~+4EV、を調整します: 最初のスライダーは-18EV~-6EVの非常に暗い部分に作用します。2つ目のスライダーは-6EV~+4EVの部分に作用します +TP_LOCALLAB_MULTIPL_TOOLTIP;トーンの幅が広い画像、-18EV~+4EV、を調整します: 最初のスライダーは-18EV~-6EVの非常に暗い部分に作用します。2つ目のスライダーは-6EV~+4EVの部分に作用します TP_LOCALLAB_NEIGH;半径 TP_LOCALLAB_NLDENOISENLGAM_TOOLTIP;値を低くすると詳細と質感が保たれます。高くするとノイズ除去が強まります。\nガンマが3.0の場合は輝度ノイズの除去には線形が使われます。 TP_LOCALLAB_NLDENOISENLPAT_TOOLTIP;処理対象の大きさに対して適用するノイズ除去の量を調節するスライダーです。 @@ -3192,8 +3187,8 @@ TP_LOCALLAB_RADIUS_TOOLTIP;半径が30より大きい場合は、高速フーリ TP_LOCALLAB_RADMASKCOL;スムーズな半径 TP_LOCALLAB_RECOTHRES02_TOOLTIP;“回復のしきい値”が1より大きい場合は、“マスクと修正領域”に付属するマスクは、その前に画像に対して行われた全ての調整を考慮しますが、現在のツールで行われた調整(例、色と明るさや、ウェーブレット、CAM16、など)は考慮しません。\n“回復のしきい値”が1より小さい場合は、“マスクと修正領域”に付属するマスクは、その前に画像に対して行われた全ての調整を考慮しません。\n\nどちらの場合も、“回復のしきい値”は現在のツール(例、色と明るさや、ウェーブレット、CAM16、など)で調整されたマスクされた画像に作用します。 TP_LOCALLAB_RECT;長方形 -TP_LOCALLAB_RECURS;参考値の繰り返し -TP_LOCALLAB_RECURS_TOOLTIP;各機能の適用後に参考値を強制的に再計算させる機能です\nマスクを使った作業にも便利です +TP_LOCALLAB_RECURS;基準値を繰り返し更新 +TP_LOCALLAB_RECURS_TOOLTIP;各機能の適用後に基準値を強制的に再計算させる機能です\nマスクを使った作業にも便利です TP_LOCALLAB_REN_DIALOG_LAB;新しいコントロールスポットの名前を入力 TP_LOCALLAB_REN_DIALOG_NAME;コントロールスポットの名前変更 TP_LOCALLAB_REPARCOL_TOOLTIP;元画像に関する色と明るさの構成の相対的強さを調整出来るようにします。 @@ -3215,12 +3210,12 @@ TP_LOCALLAB_RETI;霞除去 & レティネックス TP_LOCALLAB_RETIFRA;レティネックス TP_LOCALLAB_RETIFRAME_TOOLTIP;画像処理においてレティネックスは便利な機能です\nぼけた、霧かかった、或いは霞んだ画像を補正出来ます\nこういった画像は輝度に大きな違いがあるのが特徴です\n特殊効果を付けるためにも使えます(トーンマッピング) TP_LOCALLAB_RETIM;独自のレティネックス -TP_LOCALLAB_RETITOOLFRA;高度なレティネックス機能 +TP_LOCALLAB_RETITOOLFRA;レティネックス機能 TP_LOCALLAB_RETI_LIGHTDARK_TOOLTIP;'明度=1'或いは'暗さ=2'の場合は効果がありません\n他の値の場合は、最終工程で'マルチスケールレティネックス'('ローカルコントラスト'の調整に似ています)が適用されます。'強さ'に関わる2つのスライダーでローカルコントラストのアップストリーの処理が調整されます TP_LOCALLAB_RETI_LIMDOFFS_TOOLTIP;効果の最適化を図るため内部の変数を変えます\n'修復されたデータ'は最低値が0、最大値が32768(対数モード)に近いことが望ましいのですが、必ずしも一致させる必要はありません。 TP_LOCALLAB_RETI_LOGLIN_TOOLTIP;対数モードを使うとコントラストが増えますが、ハロが発生することもあります TP_LOCALLAB_RETI_NEIGH_VART_TOOLTIP;半径と分散(バリアンス)のスライダーは霞を調整します。前景或いは背景を目標にします -TP_LOCALLAB_RETI_SCALE_TOOLTIP;スケールが1の時は、レティネックスはローカルコントラストを調整した様な効果になります\nスケールの値を増やすと回帰作用が強化されますが、その分処理時間も増加します +TP_LOCALLAB_RETI_SCALE_TOOLTIP;スケールが1の時は、レティネックスはローカルコントラストを調整した様な効果になります\nスケールの値を増やすと回帰作用が強化されますが、その分処理時間も増加します TP_LOCALLAB_RET_TOOLNAME;霞除去 & レティネックス TP_LOCALLAB_REWEI;再加重平均の繰り返し TP_LOCALLAB_RGB;RGB トーンカーブ @@ -3238,7 +3233,7 @@ TP_LOCALLAB_SCOPEMASK_TOOLTIP;ΔE画像のマスクが有効の場合に使え TP_LOCALLAB_SENSI;スコープ TP_LOCALLAB_SENSIEXCLU;スコープ TP_LOCALLAB_SENSIEXCLU_TOOLTIP;除外される色を調整します -TP_LOCALLAB_SENSIMASK_TOOLTIP;共通なマスクに付属するスコープを調整します\n元画像とマスクの違いに対して作用します\nRT-スポットの中心の輝度、色度、色相参考値を使います\n\nマスク自体のΔEを調整することも出来ます。'設定'の中の”スコープ(ΔE画像のマスク)”を使います。 +TP_LOCALLAB_SENSIMASK_TOOLTIP;共通なマスクに付属するスコープを調整します\n元画像とマスクの違いに対して作用します\nRT-スポットの中心の輝度、色度、色相の基準値を使います\n\nマスク自体のΔEを調整することも出来ます。'設定'の中の”スコープ(ΔE画像のマスク)”を使います。 TP_LOCALLAB_SENSI_TOOLTIP;スコープの作用を加減します:\n小さい値を設定すると、色に対する作用はRT-スポットの中心部付近に限定されます\n高い値を設定すると、広範囲の色に作用が及びます TP_LOCALLAB_SETTINGS;設定 TP_LOCALLAB_SH1;シャドウ/ハイライト @@ -3271,24 +3266,24 @@ TP_LOCALLAB_SHOWFOURIER;フーリエ (DCT) TP_LOCALLAB_SHOWLAPLACE;Δ ラプラシアン (一次) TP_LOCALLAB_SHOWLC;マスクと修正領域 TP_LOCALLAB_SHOWMASK;マスクの表示 -TP_LOCALLAB_SHOWMASKCOL_TOOLTIP;マスクと修正箇所の表示:\n注意:一度に一つの機能のマスクしか見ることが出来きません\n調整及び修正した画像:機能による調整とマスクによる修正の両方を含む画像を表示\n修正された領域をマスクなしで表示:マスクを適用する前の修正領域を表示\n修正された領域をマスクと共に表示:マスクを適用した修正領域を表示\nマスクの表示:カーブやフィルタの効果を含めたマスクの様子を表示します\nスポットの構造を表示:'スポットの構造'スライダー(機能水準が高度の場合)が有効になった時に、構造検出マスクを見ることが出来ます\n注意:形状検出のアルゴリズムが作用する前にマスクが適用されます +TP_LOCALLAB_SHOWMASKCOL_TOOLTIP;マスクと修正箇所の表示:\n注意:一度に一つの機能のマスクしか見ることが出来きません\n調整及び修正した画像:機能による調整とマスクによる修正の両方を含む画像を表示\n修正領域をマスクなしで表示:マスクを適用する前の修正領域を表示\n修正領域をマスクと共に表示:マスクを適用した修正領域を表示\nマスクの表示:カーブやフィルタの効果を含めたマスクの様子を表示します\nスポットの構造を表示:'スポットの構造'スライダー(機能水準が高度の場合)が有効になった時に、構造検出マスクを見ることが出来ます\n注意:形状検出のアルゴリズムが作用する前にマスクが適用されます TP_LOCALLAB_SHOWMASKSOFT_TOOLTIP;フーリエ変換による処理を段階的に見ることが出来ます\nラプラス - しきい値の関数としてラプラス変換の2次微分を計算仕します\nフーリエ - 離散コサイン変換(DCT)でラプラス変換を表示します\nポアソン - ポアソン方程式の解を表示します\n輝度の標準化なし - 輝度の標準化なしで結果を表示します TP_LOCALLAB_SHOWMASKTYP1;ぼかし&ノイズ除去 TP_LOCALLAB_SHOWMASKTYP2;ノイズ除去 TP_LOCALLAB_SHOWMASKTYP3;ぼかし&ノイズ除去 + ノイズ除去 TP_LOCALLAB_SHOWMASKTYP_TOOLTIP;‘マスクと修正領域’と併せて使うことが出来ます。\n‘ぼかしとノイズ’を選択した場合、マスクはノイズ除去には使えません。\n‘ノイズ除去を選択した場合、マスクは’ぼかしとノイズ‘には使えません。\n’ぼかしとノイズ + ノイズ除去‘を選択した場合は、マスクを共有することが出来ます。但し、この場合、’ぼかしとノイズ‘とノイズ除去のスコープスライダーが有効となるので、修正を行う際には’マスクと共に修正領域を表示‘のオプションを使うことを奨めます。 TP_LOCALLAB_SHOWMNONE;調整及び修正した画像 -TP_LOCALLAB_SHOWMODIF;修正された領域をマスクなしで表示 +TP_LOCALLAB_SHOWMODIF;修正領域をマスクなしで表示 TP_LOCALLAB_SHOWMODIF2;マスクの表示 -TP_LOCALLAB_SHOWMODIFMASK;修正された領域をマスクと共に表示 +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_SHOWSTRUC;スポットの構造を表示 +TP_LOCALLAB_SHOWSTRUCEX;スポットの構造を表示 TP_LOCALLAB_SHOWT;マスクと修正領域 TP_LOCALLAB_SHOWVI;マスクと修正領域 TP_LOCALLAB_SHRESFRA;シャドウ/ハイライト&TRC @@ -3301,7 +3296,7 @@ TP_LOCALLAB_SIGMOIDBL;ブレンド TP_LOCALLAB_SIGMOIDLAMBDA;コントラスト TP_LOCALLAB_SIGMOIDQJ;ブラックEvとホワイトEvを使う TP_LOCALLAB_SIGMOIDTH;しきい値(グレーポイント) -TP_LOCALLAB_SIGMOID_TOOLTIP;'CIECAM'(或いは’Jz)と'シグモイド'関数を使って、トーンマッピングの様な効果を作ることが出来ます。\n3つのスライダーを使います: a) コントラストのスライダーはシグモイドの形状を変えることで強さを変えます。 b) しきい値(グレーポイント)のスライダーは、輝度に応じて作用を変えます。 c)ブレンドは画像の最終的なコントラストや輝度を変えます。 +TP_LOCALLAB_SIGMOID_TOOLTIP;'CIECAM'(或いは’Jz)と'シグモイド'関数を使って、トーンマッピングの様な効果を作ることが出来ます。\n3つのスライダーを使います: a) コントラストのスライダーはシグモイドの形状を変えることで強さを変えます。 b) しきい値(グレーポイント)のスライダーは、輝度に応じて作用を変えます。 c)ブレンドは画像の最終的なコントラストや輝度を変えます。 TP_LOCALLAB_SLOMASKCOL;スロープ TP_LOCALLAB_SLOMASK_TOOLTIP;ガンマとスロープを調整することで、不連続を避けるための“L”の漸進的修正により、アーティファクトの無いマスクの修正が出来ます TP_LOCALLAB_SLOSH;スロープ @@ -3313,10 +3308,10 @@ TP_LOCALLAB_SOFTRADIUSCOL_TOOLTIP;アーティファクトの発生を軽減す TP_LOCALLAB_SOFTRETI;ΔEアーティファクトの軽減 TP_LOCALLAB_SOFT_TOOLNAME;ソフトライト & 独自のレティネックス TP_LOCALLAB_SOURCE_ABS;絶対輝度 -TP_LOCALLAB_SOURCE_GRAY;値 +TP_LOCALLAB_SOURCE_GRAY;平均輝度(Y%) TP_LOCALLAB_SPECCASE;特有の設定 TP_LOCALLAB_SPECIAL;RGBカーブの特殊な利用 -TP_LOCALLAB_SPECIAL_TOOLTIP;チェックボックスに✔を入れると、他の全ての作用が取り除かれます。例えば、“スコープ”, マスク, スライダーなどの作用(境界を除きます) が除かれRGBトーンカーブの効果だけが使われます +TP_LOCALLAB_SPECIAL_TOOLTIP;チェックボックスに✔を入れると、他の全ての作用が取り除かれます。例えば、“スコープ”, マスク, スライダーなどの作用(境界を除きます) が除かれRGBトーンカーブの効果だけが使われます TP_LOCALLAB_SPOTNAME;新しいスポット TP_LOCALLAB_STD;標準 TP_LOCALLAB_STR;強さ @@ -3360,10 +3355,10 @@ TP_LOCALLAB_TOOLMASK_2;ウェーブレット TP_LOCALLAB_TOOLMASK_TOOLTIP;'機能としての構造のマスク'のオプションを有効にして、構造マスク(スライダー)を使う:この場合、構造を表示するマスクは、1回以上2つのカーブ、L(L)或いはLC(H)が変更された後に生成されます\nここで、'構造マスク'は他のマスクの様な機能を果たします:ガンマ、スロープなど\n画像の構造に応じてマスクの作用を変えられます。このオプションは'ΔE画像のマスク'と付随する'スコープ(Δ”画像のマスク)'に敏感に作用します TP_LOCALLAB_TRANSIT;境界の階調調整 TP_LOCALLAB_TRANSITGRAD;XY軸方向の境界の差別 -TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Y軸方向の作用の領域を変えることが出来ます +TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Y軸方向の作用の領域を変えることが出来ます TP_LOCALLAB_TRANSITVALUE;境界値 TP_LOCALLAB_TRANSITWEAK;境界値の減衰(線形~Log) -TP_LOCALLAB_TRANSITWEAK_TOOLTIP;境界値の減衰を調節 : 処理の滑らかさを変える - 1 線形 - 2 パラボリック - 3~25乗\n非常に低い境界値と併せれば、CBDL、ウェーブレット、色と明るさを使った不良部分の補正に使うことが出来ます。 +TP_LOCALLAB_TRANSITWEAK_TOOLTIP;境界値の減衰を調節 : 処理の滑らかさを変える - 1 線形 - 2 パラボリック - 3~25乗\n非常に低い境界値と併せれば、CBDL、ウェーブレット、色と明るさを使った不良部分の補正に使うことが出来ます。 TP_LOCALLAB_TRANSIT_TOOLTIP;RT-スポットの中心円からフレームの間で作用が働く領域と作用が減衰する領域の境界を、中心円からフレームまでの%で調整します TP_LOCALLAB_TRANSMISSIONGAIN;透過のゲイン TP_LOCALLAB_TRANSMISSIONMAP;透過マップ @@ -3434,7 +3429,7 @@ TP_METADATA_MODE;メタデータ コピーモード TP_METADATA_STRIP;メタデータを全て取り除く TP_METADATA_TUNNEL;変更なしでコピー TP_NEUTRAL;リセット -TP_NEUTRAL_TOOLTIP;露光量補正のスライダー値をニュートラルにリセットします。\n自動露光補正の調整値ついても同様にリセットされます +TP_NEUTRAL_TIP;露光量補正のスライダー値をニュートラルにリセットします。\n自動露光補正の調整値ついても同様にリセットされます TP_PCVIGNETTE_FEATHER;フェザー TP_PCVIGNETTE_FEATHER_TOOLTIP;フェザー: 0=四隅だけ、50=中央までの半分、100=中央まで TP_PCVIGNETTE_LABEL;ビネットフィルター @@ -3544,34 +3539,34 @@ TP_RAW_LMMSE_TOOLTIP;ガンマ追加 (step 1) - メディアン追加 (step 2,3, TP_RAW_MONO;Mono TP_RAW_NONE;なし (センサーのパターンを表示) TP_RAW_PIXELSHIFT;ピクセルシフト -TP_RAW_PIXELSHIFTAVERAGE;ブレのある部分の平均を使う +TP_RAW_PIXELSHIFTAVERAGE;動体部分に平均を使う TP_RAW_PIXELSHIFTAVERAGE_TOOLTIP;ブレのある部分の特定のフレームを使う代わりに、全てのフレームの平均を使う\nブレの少ない(オーバーラップ)対象にブレの効果を施す -TP_RAW_PIXELSHIFTBLUR;ブレのマスクのぼかし -TP_RAW_PIXELSHIFTDMETHOD;ブレに対するデモザイクの方式 +TP_RAW_PIXELSHIFTBLUR;動体マスクのぼかし +TP_RAW_PIXELSHIFTDMETHOD;動体に対するデモザイクの方式 TP_RAW_PIXELSHIFTEPERISO;感度 TP_RAW_PIXELSHIFTEPERISO_TOOLTIP;通常のISOに関してはデフォルトの0で十分だと思われます。\n高いISOの場合は、振れの検知を良くするために設定値を上げます。\n少しづつ増加させ、振れのマスクの変化を見ます。 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_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_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値の画像には十分です。\nISO値の高い画像ではスライダーの値を増やします。5.0から始めるのがいいでしょう。\n設定値を変えながら振れマスクを見極めます。 TP_RAW_PIXELSHIFTSMOOTH;境界部分を滑らかにする -TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;これはブレのある領域とブレがない領域の境を滑らかに補正するものです。\n0に設定すると機能の働きはありません。\n1に設定すると、選択された構成画像にAMaZEかLMMSEが使われた結果が得られます("LMMSEを使う"というオプション次第)、或いは"メディアンを使う"が選択されていれば全ての構成画像にメディアンが使われます。 +TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;これは動体部分とそうでない部分の境を滑らかに補正するものです。\n0に設定すると機能の働きはありません。\n1に設定すると、選択された構成画像にAMaZEかLMMSEが使われた結果が得られます("LMMSEを使う"というオプション次第)、或いは"メディアンを使う"が選択されていれば全ての構成画像にメディアンが使われます。 TP_RAW_RCD;RCD TP_RAW_RCDBILINEAR;RCD+バイリニア補間 TP_RAW_RCDVNG4;RCD+VNG4 @@ -3847,7 +3842,7 @@ TP_WAVELET_DENCURV;カーブ TP_WAVELET_DENL;補正の構造 TP_WAVELET_DENLH;レベル1~4のガイド付きしきい値 TP_WAVELET_DENLOCAL_TOOLTIP;ローカルコントラストに応じてノイズ除去を行うためにカーブを使います\nノイズが除去される領域は構造が保たれます。 -TP_WAVELET_DENMIX_TOOLTIP;ローカルコントラストの参考値はガイド付きフィルタで使われます。\n画像次第で、ノイズのレベル計測がノイズ除去処理の前か後になるかで結果が変わります。これら4つの選択の中から、元画像と修正(ノイズ除去)画像の間で最も妥協できるものを選びます。 +TP_WAVELET_DENMIX_TOOLTIP;ローカルコントラストの基準値はガイド付きフィルタで使われます。\n画像次第で、ノイズのレベル計測がノイズ除去処理の前か後になるかで結果が変わります。これら4つの選択の中から、元画像と修正(ノイズ除去)画像の間で最も妥協できるものを選びます。 TP_WAVELET_DENOISE;ローカルコントラストをベースにしたガイド付きカーブ TP_WAVELET_DENOISEGUID;色相をベースにしたガイド付きしきい値 TP_WAVELET_DENOISEH;番手の高いレベルのカーブ ローカルコントラスト @@ -3930,7 +3925,7 @@ TP_WAVELET_MEDILEV;エッジ検出 TP_WAVELET_MEDILEV_TOOLTIP;エッジの検出を有効にした際には、次の操作が奨められます:\n- アーティファクト発生を避けるため低いレベルのコントラストを使わない\n- グラデーション感度では高い値を使う\n\n効果を和らげるには、ノイズ低減とリファインの’リファイン’を下げる TP_WAVELET_MERGEC;色調の融合 TP_WAVELET_MERGEL;輝度の融合 -TP_WAVELET_MIXCONTRAST;参考値 +TP_WAVELET_MIXCONTRAST;基準値 TP_WAVELET_MIXDENOISE;ノイズ除去 TP_WAVELET_MIXMIX;混成 50%ノイズ - 50%ノイズ除去 TP_WAVELET_MIXMIX70;混成 30%ノイズ - 70%ノイズ除去 @@ -3986,7 +3981,7 @@ TP_WAVELET_STRENGTH;強さ TP_WAVELET_SUPE;エキストラ TP_WAVELET_THR;シャドウのしきい値 TP_WAVELET_THRDEN_TOOLTIP;ローカルコントラストに応じたノイズ除去の目安に使うため、ステップカーブを作成します。ノイズ除去がコントラストの低い均一な画質部分に適用されます。詳細がある部分(コントラストが高い)は保持されます。 -TP_WAVELET_THREND;ローカルコントラストのしきい値 +TP_WAVELET_THREND;ローカルコントラストのしきい値 TP_WAVELET_THRESHOLD;調整レベル(小さいディテール) TP_WAVELET_THRESHOLD2;調整レベル(大きいディテール) TP_WAVELET_THRESHOLD2_TOOLTIP;設定値より上のレベルだけが、大きなディテールのレベルの輝度範囲で設定された条件で調整されます。 @@ -4074,10 +4069,4 @@ ZOOMPANEL_ZOOMOUT;ズームアウト\nショートカット: - ! Untranslated keys follow; remove the ! prefix after an entry is translated. !!!!!!!!!!!!!!!!!!!!!!!!! -!TC_PRIM_BLUX;Bx -!TC_PRIM_BLUY;By -!TC_PRIM_GREX;Gx -!TC_PRIM_GREY;Gy -!TC_PRIM_REDX;Rx -!TC_PRIM_REDY;Ry -!TP_LOCALLAB_LOGAUTOGRAYJZ_TOOLTIP;Automatically calculates the 'Mean luminance' for the scene conditions. +!TP_NEUTRAL_TOOLTIP;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. diff --git a/rtdata/languages/default b/rtdata/languages/default index 775b098f4..10d0a89c3 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -61,6 +61,7 @@ EXIFFILTER_IMAGETYPE;Image type EXIFFILTER_ISO;ISO EXIFFILTER_LENS;Lens EXIFFILTER_METADATAFILTER;Enable metadata filters +EXIFFILTER_PATH;File path EXIFFILTER_SHUTTER;Shutter EXIFPANEL_ADDEDIT;Add/Edit EXIFPANEL_ADDEDITHINT;Add new tag or edit tag. @@ -165,6 +166,7 @@ FILEBROWSER_POPUPREMOVE;Delete permanently FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version FILEBROWSER_POPUPRENAME;Rename FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPSORTBY;Sort Files FILEBROWSER_POPUPTRASH;Move to trash FILEBROWSER_POPUPUNRANK;Unrank FILEBROWSER_POPUPUNTRASH;Remove from trash @@ -208,6 +210,7 @@ FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size.\n\nShortcuts:\n- - Multi FILECHOOSER_FILTER_ANY;All files FILECHOOSER_FILTER_COLPROF;Color profiles (*.icc) FILECHOOSER_FILTER_CURVE;Curve files +FILECHOOSER_FILTER_EXECUTABLE;Executable files FILECHOOSER_FILTER_LCP;Lens correction profiles FILECHOOSER_FILTER_PP;Processing profiles FILECHOOSER_FILTER_SAME;Same format as current photo @@ -235,6 +238,7 @@ GENERAL_NO;No GENERAL_NONE;None GENERAL_OK;OK GENERAL_OPEN;Open +GENERAL_OTHER;Other GENERAL_PORTRAIT;Portrait GENERAL_RESET;Reset GENERAL_SAVE;Save @@ -1404,18 +1408,22 @@ 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_FF_FROMMETADATA;Flat-Field - From Metadata HISTORY_MSG_FILMNEGATIVE_BALANCE;FN - Reference output HISTORY_MSG_FILMNEGATIVE_COLORSPACE;Film negative color space HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative HISTORY_MSG_FILMNEGATIVE_REF_SPOT;FN - Reference input HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values +HISTORY_MSG_GAMUTMUNSEL;Gamut-Munsell HISTORY_MSG_HISTMATCHING;Auto-matched tone curve HISTORY_MSG_HLBL;Color propagation - blur +HISTORY_MSG_HLTH;Inpaint opposed - gain threshold HISTORY_MSG_ICL_LABGRIDCIEXY;Cie xy HISTORY_MSG_ICM_AINTENT;Abstract profile intent HISTORY_MSG_ICM_BLUX;Primaries Blue X HISTORY_MSG_ICM_BLUY;Primaries Blue Y HISTORY_MSG_ICM_FBW;Black and White +HISTORY_MSG_ICM_GAMUT;Gamut control HISTORY_MSG_ICM_GREX;Primaries Green X HISTORY_MSG_ICM_GREY;Primaries Green Y HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries @@ -1435,6 +1443,7 @@ 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_LOCAL_GAMUTMUNSEL;Local - Gamut-Munsell HISTORY_MSG_METADATA_MODE;Metadata copy mode HISTORY_MSG_MICROCONTRAST_CONTRAST;Microcontrast - Contrast threshold HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - Auto threshold @@ -1618,7 +1627,7 @@ MAIN_BUTTON_PREFERENCES;Preferences MAIN_BUTTON_PUTTOQUEUE_TOOLTIP;Put current image to processing queue.\nShortcut: Ctrl+b MAIN_BUTTON_SAVE_TOOLTIP;Save current image.\nShortcut: Ctrl+s\nSave current profile (.pp3).\nShortcut: Ctrl+Shift+s MAIN_BUTTON_SENDTOEDITOR;Edit image in external editor -MAIN_BUTTON_SENDTOEDITOR_TOOLTIP;Edit current image in external editor.\nShortcut: Ctrl+e +MAIN_BUTTON_SENDTOEDITOR_TOOLTIP;Edit current image in external editor.\nShortcut: Ctrl+e\nCurrent editor: MAIN_BUTTON_SHOWHIDESIDEPANELS_TOOLTIP;Show/hide all side panels.\nShortcut: m MAIN_BUTTON_UNFULLSCREEN;Exit fullscreen MAIN_FRAME_EDITOR;Editor @@ -1734,6 +1743,7 @@ PARTIALPASTE_EXPOSURE;Exposure PARTIALPASTE_FILMNEGATIVE;Film negative PARTIALPASTE_FILMSIMULATION;Film simulation PARTIALPASTE_FLATFIELDAUTOSELECT;Flat-field auto-selection +PARTIALPASTE_FLATFIELDFROMMETADATA;Flat-field from Metadata PARTIALPASTE_FLATFIELDBLURRADIUS;Flat-field blur radius PARTIALPASTE_FLATFIELDBLURTYPE;Flat-field blur type PARTIALPASTE_FLATFIELDCLIPCONTROL;Flat-field clip control @@ -1868,6 +1878,10 @@ PREFERENCES_EXTEDITOR_DIR_CUSTOM;Custom PREFERENCES_EXTEDITOR_DIR_TEMP;OS temp dir PREFERENCES_EXTEDITOR_FLOAT32;32-bit float TIFF output PREFERENCES_EXTERNALEDITOR;External Editor +PREFERENCES_EXTERNALEDITOR_CHANGE;Change Application +PREFERENCES_EXTERNALEDITOR_CHANGE_FILE;Change Executable +PREFERENCES_EXTERNALEDITOR_COLUMN_NAME;Name +PREFERENCES_EXTERNALEDITOR_COLUMN_COMMAND;Command PREFERENCES_FBROWSEROPTS;File Browser / Thumbnail Options PREFERENCES_FILEBROWSERTOOLBARSINGLEROW;Compact toolbars in File Browser PREFERENCES_FLATFIELDFOUND;Found @@ -1965,6 +1979,7 @@ PREFERENCES_STARTUPIMDIR;Image Directory at Startup PREFERENCES_TAB_BROWSER;File Browser PREFERENCES_TAB_COLORMGR;Color Management PREFERENCES_TAB_DYNAMICPROFILE;Dynamic Profile Rules +PREFERENCES_TAB_FAVORITES;Favorites PREFERENCES_TAB_GENERAL;General PREFERENCES_TAB_IMPROC;Image Processing PREFERENCES_TAB_PERFORMANCE;Performance @@ -1973,6 +1988,12 @@ 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 +PREFERENCES_TOOLPANEL_AVAILABLETOOLS;Available Tools +PREFERENCES_TOOLPANEL_CLONE_FAVORITES;Keep favorite tools in original locations +PREFERENCES_TOOLPANEL_CLONE_FAVORITES_TOOLTIP;If set, favorite tools will appear in both the favorites tab and their original tabs.\n\nNote: Enabling this option may result in a slight delay when switching tabs. +PREFERENCES_TOOLPANEL_FAVORITE;Favorite +PREFERENCES_TOOLPANEL_FAVORITESPANEL;Favorites Panel +PREFERENCES_TOOLPANEL_TOOL;Tool PREFERENCES_TP_LABEL;Tool panel: PREFERENCES_TP_VSCROLLBAR;Hide vertical scrollbar PREFERENCES_USEBUNDLEDPROFILES;Use bundled profiles @@ -2040,6 +2061,7 @@ SAMPLEFORMAT_16;16-bit floating-point SAMPLEFORMAT_32;24-bit floating-point SAMPLEFORMAT_64;32-bit floating-point SAVEDLG_AUTOSUFFIX;Automatically add a suffix if the file already exists +SAVEDLG_BIGTIFF;BigTIFF (no metadata support) SAVEDLG_FILEFORMAT;File format SAVEDLG_FILEFORMAT_FLOAT; floating-point SAVEDLG_FORCEFORMATOPTS;Force saving options @@ -2059,6 +2081,13 @@ SAVEDLG_WARNFILENAME;File will be named 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. +SORT_ASCENDING;Ascending +SORT_BY_NAME;By Name +SORT_BY_DATE;By Date +SORT_BY_EXIF;By EXIF +SORT_BY_RANK;By Rank +SORT_BY_LABEL;By Color Label +SORT_DESCENDING;Descending TC_PRIM_BLUX;Bx TC_PRIM_BLUY;By TC_PRIM_GREX;Gx @@ -2242,6 +2271,7 @@ TP_COLORAPP_TCMODE_LIGHTNESS;Lightness TP_COLORAPP_TCMODE_SATUR;Saturation 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_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_TEMPOUT_TOOLTIP;Temperature and Tint.\nDepending on the choices made previously, the selected temperature is:\nWhite balance\nA temp=2856\nD41 temp=4100\nD50 temp=5003\nD55 temp=5503\nD60 temp=6000\nD65 temp=6504\nD75 temp=7504\nFree. TP_COLORAPP_TONECIE;Use CIECAM for tone mapping 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, etc.), 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. @@ -2472,6 +2502,7 @@ TP_FLATFIELD_BT_VERTHORIZ;Vertical + Horizontal TP_FLATFIELD_BT_VERTICAL;Vertical 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_FLATFIELD_FROMMETADATA;From Metadata TP_FLATFIELD_LABEL;Flat-Field 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;Center @@ -2489,8 +2520,10 @@ TP_GRADIENT_STRENGTH_TOOLTIP;Filter strength in stops. TP_HLREC_BLEND;Blend TP_HLREC_CIELAB;CIELab Blending TP_HLREC_COLOR;Color Propagation +TP_HLREC_COLOROPP;Inpaint Opposed TP_HLREC_ENA_TOOLTIP;Could be activated by Auto Levels. TP_HLREC_HLBLUR;Blur +TP_HLREC_HLTH;Gain threshold TP_HLREC_LABEL;Highlight reconstruction TP_HLREC_LUMINANCE;Luminance Recovery TP_HLREC_METHOD;Method: @@ -2510,6 +2543,7 @@ 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_FBW;Black-and-White +TP_ICM_GAMUT;Gamut control TP_ICM_ILLUMPRIM_TOOLTIP;Choose the illuminant closest to the shooting conditions.\nChanges can only be made when the 'Destination primaries' selection is set to 'Custom (sliders)'. TP_ICM_INPUTCAMERA;Camera standard TP_ICM_INPUTCAMERAICC;Auto-matched camera profile @@ -2587,8 +2621,6 @@ TP_ICM_WORKING_TRC_SRGB;sRGB g=2.4 s=12.92 TP_ICM_WORKING_TRC_TOOLTIP;Only for built-in profiles. TP_IMPULSEDENOISE_LABEL;Impulse Noise Reduction TP_IMPULSEDENOISE_THRESH;Threshold -TP_LABCURVE_AVOIDCOLORSHIFT;Avoid color shift -TP_LABCURVE_AVOIDCOLORSHIFT_TOOLTIP;Fit colors into gamut of the working color space and apply Munsell correction (Uniform Perceptual Lab). TP_LABCURVE_BRIGHTNESS;Lightness TP_LABCURVE_CHROMATICITY;Chromaticity TP_LABCURVE_CHROMA_TOOLTIP;To apply B&W toning, set Chromaticity to -100. @@ -2653,7 +2685,7 @@ TP_LOCALLAB_ARTIF_TOOLTIP;ΔE scope threshold increases the range of ΔE scope. TP_LOCALLAB_AUTOGRAY;Auto mean luminance (Yb%) TP_LOCALLAB_AUTOGRAYCIE;Auto TP_LOCALLAB_AVOID;Avoid color shift -TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP;Fit colors into gamut of the working color space and apply Munsell correction (Uniform Perceptual Lab).\nMunsell correction always disabled when Jz or CAM16 is used. +TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP;Fit colors into gamut of the working color space and apply Munsell correction (Uniform Perceptual Lab).\nMunsell correction always disabled when Jz or CAM16 or Color Appearance and Lighting is used.\n\nDefault: Munsell.\nMunsell correction: fixes Lab mode hue drifts due to non-linearity, when chromaticity is changed (Uniform Perceptual Lab).\nLab: applies a gamut control, in relative colorimetric, Munsell is then applied.\nXYZ Absolute, applies gamut control, in absolute colorimetric, Munsell is then applied.\nXYZ Relative, applies gamut control, in relative colorimetric, Munsell is then applied. TP_LOCALLAB_AVOIDMUN;Munsell correction only TP_LOCALLAB_AVOIDMUN_TOOLTIP;Munsell correction always disabled when Jz or CAM16 is used. TP_LOCALLAB_AVOIDRAD;Soft radius @@ -2883,6 +2915,11 @@ TP_LOCALLAB_GAMM;Gamma TP_LOCALLAB_GAMMASKCOL;Gamma TP_LOCALLAB_GAMMASK_TOOLTIP;Adjusting Gamma and Slope can provide a soft and artifact-free transformation of the mask by progressively modifying 'L' to avoid any discontinuities. TP_LOCALLAB_GAMSH;Gamma +TP_LOCALLAB_GAMUTNON;None +TP_LOCALLAB_GAMUTLABRELA;Lab +TP_LOCALLAB_GAMUTXYZABSO;XYZ Absolute +TP_LOCALLAB_GAMUTXYZRELA;XYZ Relative +TP_LOCALLAB_GAMUTMUNSELL;Munsell only TP_LOCALLAB_GAMW;Gamma (wavelet pyramids) TP_LOCALLAB_GRADANG;Gradient angle TP_LOCALLAB_GRADANG_TOOLTIP;Rotation angle in degrees: -180 0 +180. diff --git a/rtdata/profiles/Auto-Matched Curve - ISO High.pp3 b/rtdata/profiles/Auto-Matched Curve - ISO High.pp3 index 99f0af8fe..16c9a71f5 100644 --- a/rtdata/profiles/Auto-Matched Curve - ISO High.pp3 +++ b/rtdata/profiles/Auto-Matched Curve - ISO High.pp3 @@ -4,7 +4,7 @@ HistogramMatching=true [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Directional Pyramid Denoising] Enabled=true diff --git a/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3 b/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3 index c94077b21..e6c7fb96c 100644 --- a/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3 +++ b/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3 @@ -4,7 +4,7 @@ HistogramMatching=true [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [LensProfile] LcMode=lfauto diff --git a/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3 b/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3 index f9196bb30..ffb5587b9 100644 --- a/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3 +++ b/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3 @@ -4,7 +4,7 @@ HistogramMatching=true [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Directional Pyramid Denoising] Enabled=true diff --git a/rtdata/profiles/Film Negative - Black and White.pp3 b/rtdata/profiles/Film Negative - Black and White.pp3 index ad2a38e1e..3bebe7e3c 100644 --- a/rtdata/profiles/Film Negative - Black and White.pp3 +++ b/rtdata/profiles/Film Negative - Black and White.pp3 @@ -11,7 +11,7 @@ Curve2=1;0;0;0.0397505754145333;0.020171771436200074;0.54669745433149319;0.69419 [HLRecovery] Enabled=false -Method=Blend +Method=Coloropp [Black & White] Enabled=true diff --git a/rtdata/profiles/Film Negative.pp3 b/rtdata/profiles/Film Negative.pp3 index 0ecac1d33..e76c61866 100644 --- a/rtdata/profiles/Film Negative.pp3 +++ b/rtdata/profiles/Film Negative.pp3 @@ -11,7 +11,7 @@ Curve2=1;0;0;0.0397505754145333;0.020171771436200074;0.54669745433149319;0.69419 [HLRecovery] Enabled=false -Method=Blend +Method=Coloropp [Crop] FixedRatio=false diff --git a/rtdata/profiles/Pop/Pop 1.pp3 b/rtdata/profiles/Pop/Pop 1.pp3 index 2152a268b..cbdf4ab5b 100644 --- a/rtdata/profiles/Pop/Pop 1.pp3 +++ b/rtdata/profiles/Pop/Pop 1.pp3 @@ -19,7 +19,7 @@ Curve2=0; [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Luminance Curve] Enabled=true diff --git a/rtdata/profiles/Pop/Pop 2 Lab.pp3 b/rtdata/profiles/Pop/Pop 2 Lab.pp3 index 796aeb5ba..f4c01fd1b 100644 --- a/rtdata/profiles/Pop/Pop 2 Lab.pp3 +++ b/rtdata/profiles/Pop/Pop 2 Lab.pp3 @@ -19,7 +19,7 @@ Curve2=0; [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Luminance Curve] Enabled=true diff --git a/rtdata/profiles/Pop/Pop 3 Skin.pp3 b/rtdata/profiles/Pop/Pop 3 Skin.pp3 index 650b2e189..ebce37b58 100644 --- a/rtdata/profiles/Pop/Pop 3 Skin.pp3 +++ b/rtdata/profiles/Pop/Pop 3 Skin.pp3 @@ -19,7 +19,7 @@ Curve2=0; [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Luminance Curve] Enabled=true diff --git a/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 b/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 index 9faa32a0a..1e3527ceb 100644 --- a/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 +++ b/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 @@ -19,7 +19,7 @@ Curve2=0; [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Black & White] Enabled=true diff --git a/rtdata/profiles/Standard Film Curve - ISO High.pp3 b/rtdata/profiles/Standard Film Curve - ISO High.pp3 index 4dd3a9b1d..42bbed6d3 100644 --- a/rtdata/profiles/Standard Film Curve - ISO High.pp3 +++ b/rtdata/profiles/Standard Film Curve - ISO High.pp3 @@ -6,7 +6,7 @@ Curve=1;0;0;0.11;0.089999999999999997;0.32000000000000001;0.42999999999999999;0. [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Directional Pyramid Denoising] Enabled=true diff --git a/rtdata/profiles/Standard Film Curve - ISO Low.pp3 b/rtdata/profiles/Standard Film Curve - ISO Low.pp3 index 45fcca730..342b1c8d3 100644 --- a/rtdata/profiles/Standard Film Curve - ISO Low.pp3 +++ b/rtdata/profiles/Standard Film Curve - ISO Low.pp3 @@ -6,7 +6,7 @@ Curve=1;0;0;0.11;0.089999999999999997;0.32000000000000001;0.42999999999999999;0. [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [LensProfile] LcMode=lfauto diff --git a/rtdata/profiles/Standard Film Curve - ISO Medium.pp3 b/rtdata/profiles/Standard Film Curve - ISO Medium.pp3 index 4aff630f5..f3b292094 100644 --- a/rtdata/profiles/Standard Film Curve - ISO Medium.pp3 +++ b/rtdata/profiles/Standard Film Curve - ISO Medium.pp3 @@ -6,7 +6,7 @@ Curve=1;0;0;0.11;0.089999999999999997;0.32000000000000001;0.42999999999999999;0. [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Directional Pyramid Denoising] Enabled=true diff --git a/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css b/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css index dd7be3bfd..07a0bd65d 100644 --- a/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css +++ b/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css @@ -760,6 +760,23 @@ button.radio#histButton:hover { margin-right: 0.25em; } +/* ExpanderContents is just a logical container. Don't add additional spacing. */ +#ExpanderBox > .ExpanderContents > * { + margin: 0; + min-height: 0; + padding: 0; +} + +/* For sub-tools containers that go below another widget, add some margin + * between them if the container has children. */ +#MyExpander .SubToolsContainer:not(:first-child) > :first-child { + margin-top: 0.1666666666666666em; +} + +#MyExpander .SubToolsContainer { + min-height: 0; +} + /* Tool background */ #ExpanderBox > box, #ExpanderBox > grid { background-color: #363636; @@ -808,9 +825,11 @@ button.radio#histButton:hover { } #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 { +#ExpanderBox > .ExpanderContents > box:not(.SubToolsContainer) > checkbutton, #ExpanderBox > .ExpanderContents > box:not(.SubToolsContainer) > box, #ExpanderBox > .ExpanderContents > grid > checkbutton, #ExpanderBox > .ExpanderContents > box:not(.SubToolsContainer) > grid, #ExpanderBox > .ExpanderContents > grid > grid, #ExpanderBox frame > box > grid, #ExpanderBox frame > grid > grid, #ExpanderBox frame > grid > box, +#ExpanderBox2 > .ExpanderContents > box:not(.SubToolsContainer) > checkbutton, #ExpanderBox2 > .ExpanderContents > box:not(.SubToolsContainer) > box, #ExpanderBox2 > .ExpanderContents > grid > checkbutton, #ExpanderBox2 > .ExpanderContents > box:not(.SubToolsContainer) > grid, #ExpanderBox2 > .ExpanderContents > grid > grid, #ExpanderBox2 frame > box > grid, #ExpanderBox2 frame > grid > grid, #ExpanderBox2 frame > grid > box, +#ExpanderBox2 > box:not(.ExpanderContents) > checkbutton, #ExpanderBox2 > box:not(.ExpanderContents) > box, #ExpanderBox2 > grid > checkbutton, #ExpanderBox2 > box:not(.ExpanderContents) > grid, #ExpanderBox2 > grid > grid, #ExpanderBox2 frame > box > grid, #ExpanderBox2 frame > grid > grid, #ExpanderBox2 frame > grid > box, +#ExpanderBox3 > .ExpanderContents > box:not(.SubToolsContainer) > checkbutton, #ExpanderBox3 > .ExpanderContents > box:not(.SubToolsContainer) > box, #ExpanderBox3 > .ExpanderContents > grid > checkbutton, #ExpanderBox3 > .ExpanderContents > box:not(.SubToolsContainer) > grid, #ExpanderBox3 > .ExpanderContents > grid > grid, #ExpanderBox3 frame > box > grid, #ExpanderBox3 frame > grid > grid, #ExpanderBox3 frame > grid > box, +#ExpanderBox3 > box:not(.ExpanderContents) > checkbutton, #ExpanderBox3 > box:not(.ExpanderContents) > box, #ExpanderBox3 > grid > checkbutton, #ExpanderBox3 > box:not(.ExpanderContents) > grid, #ExpanderBox3 > grid > grid, #ExpanderBox3 frame > box > grid, #ExpanderBox3 frame > grid > grid, #ExpanderBox3 frame > grid > box { margin-top: 0.1666666666666666em; } @@ -1099,6 +1118,10 @@ dialog frame > label:not(.dummy) { min-width: 25em; } +#ToolPanelNotebook .PanelEnding { + margin-top: 4px; +} + #ToolPanelNotebook header { background-color: #383838; border-color: #262626; @@ -1395,4 +1418,4 @@ progressbar progress { .grid-spacing > * { margin: 0.1666666666666666em; -} \ No newline at end of file +} diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index 57c6db148..2e314510a 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -758,7 +758,7 @@ button.radio#histButton:hover { #MyExpander:first-child { border-top: none; } -#MyExpander:nth-last-child(2), +#MyExpander:nth-last-child(1), #MyExpander #MyExpander:nth-last-child(1) { border-bottom: 0.0833333333333333em solid rgba(0,0,0,0.3); } @@ -766,6 +766,29 @@ button.radio#histButton:hover { border-bottom: none; } +/* ExpanderContents is just a logical container. Don't add additional spacing. */ +#ExpanderBox > .ExpanderContents > * { + margin: 0; + min-height: 0; + padding: 0; +} + +/* For sub-tools containers that go below another widget, add some margin + * between them if the container has children. */ +#MyExpander .SubToolsContainer:not(:first-child) > :first-child { + margin-top: 0.3333333333333333em; +} + +#MyExpander .SubToolsContainer { + min-height: 0; +} + +.SubToolsContainer > #MyExpander, +.ToolParamBlock > #MyExpander, +.ExpanderContents, +#MyExpander .ToolParamBlock { + margin: 0; +} /* Tool background */ #ExpanderBox > box, @@ -1046,6 +1069,10 @@ dialog frame > label:not(.dummy) { padding: 0; } +#ToolPanelNotebook .PanelEnding { + margin-top: 4px; +} + #ToolPanelNotebook header tabs { padding: 0.0833333333333333em; background-color: #2A2A2A; diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css index 4e7e192ad..ba25e70b7 100644 --- a/rtdata/themes/TooWaBlue-GTK3-20_.css +++ b/rtdata/themes/TooWaBlue-GTK3-20_.css @@ -963,6 +963,9 @@ window.csd:not(.fullscreen) #MainNotebook > header.top { #ToolPanelNotebook { background-color: @bg-dark-grey; } +#ToolPanelNotebook .PanelEnding { + margin-top: 4px; +} #ToolPanelNotebook > header { border-bottom: 0.083333333333333333em solid @view-grid-border; margin-left: 0.083333333333333333em; @@ -1278,6 +1281,11 @@ menuitem:hover > * { color: @text-hl-color; } +menu menuitem > radio + * image:not(.dummy), +#MyExpander menu menuitem > radio + * image:not(.dummy) { + margin-left: 1pt; +} + menu image:not(.dummy), #MyExpander menu image:not(.dummy) { min-height: 2em; diff --git a/rtdata/themes/size - Legacy.css b/rtdata/themes/size - Legacy.css index 08c39f973..089a909ee 100644 --- a/rtdata/themes/size - Legacy.css +++ b/rtdata/themes/size - Legacy.css @@ -383,6 +383,11 @@ menu arrow { margin: 0 -0.25em 0 0; } +menu menuitem > radio + * image:not(.dummy), +#MyExpander menu menuitem > radio + * image:not(.dummy) { + margin-left: 1pt; +} + menu image:not(.dummy), #MyExpander menu image:not(.dummy) { min-height: 2em; @@ -1029,4 +1034,4 @@ messagedialog headerbar button.titlebutton { min-height: 1.25em; margin: 0; } -/*** end ***************************************************************************************/ \ No newline at end of file +/*** end ***************************************************************************************/ diff --git a/rtdata/themes/size.css b/rtdata/themes/size.css index 2d23bf860..675ed51c2 100644 --- a/rtdata/themes/size.css +++ b/rtdata/themes/size.css @@ -351,6 +351,11 @@ menu arrow { margin: 0 -0.25em 0 0; } +menu menuitem > radio + * image:not(.dummy), +#MyExpander menu menuitem > radio + * image:not(.dummy) { + margin-left: 1pt; +} + menu image:not(.dummy), #MyExpander menu image:not(.dummy) { min-height: 2em; diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 1f3cf352b..c657d6f9d 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -176,6 +176,19 @@ if(LENSFUN_HAS_LOAD_DIRECTORY) set_source_files_properties(rtlensfun.cc PROPERTIES COMPILE_DEFINITIONS RT_LENSFUN_HAS_LOAD_DIRECTORY) endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.0") + # procparams.cc takes a long time to compile with optimizations starting + # with GCC 12.1 due to PTA (see issue #6548) + get_source_file_property(PROCPARAMS_COMPILE_OPTIONS procparams.cc COMPILE_OPTIONS) + if(PROCPARAMS_COMPILE_OPTIONS STREQUAL "NOTFOUND") + set(PROCPARAMS_COMPILE_OPTIONS "") + else() + set(PROCPARAMS_COMPILE_OPTIONS "${PROCPARAMS_COMPILE_OPTIONS};") + endif() + set(PROCPARAMS_COMPILE_OPTIONS "${PROCPARAMS_COMPILE_OPTIONS}-fno-tree-pta") + set_source_files_properties(procparams.cc PROPERTIES COMPILE_OPTIONS ${PROCPARAMS_COMPILE_OPTIONS}) +endif() + if(WITH_BENCHMARK) add_definitions(-DBENCHMARK) endif() diff --git a/rtengine/array2D.h b/rtengine/array2D.h index 10d797999..eee6c3210 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -248,6 +248,14 @@ public: return *this; } + // import from flat data + void operator()(std::size_t w, std::size_t h, const T* const copy) + { + ar_realloc(w, h); + for (std::size_t y = 0; y < h; ++y) { + std::copy(copy + y * w, copy + y * w + w, rows.data()[y]); + } + } int getWidth() const { diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index aab2a252c..64fc4d4ba 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -28,8 +28,6 @@ namespace rtengine CameraConst::CameraConst() : pdafOffset(0) { memset(dcraw_matrix, 0, sizeof(dcraw_matrix)); - memset(raw_crop, 0, sizeof(raw_crop)); - memset(raw_mask, 0, sizeof(raw_mask)); white_max = 0; globalGreenEquilibration = -1; } @@ -192,6 +190,68 @@ CameraConst* CameraConst::parseEntry(const void *cJSON_, const char *make_model) std::unique_ptr cc(new CameraConst); cc->make_model = make_model; + const auto get_raw_crop = + [](int w, int h, const cJSON *ji, CameraConst *cc) -> bool + { + std::array rc; + + if (ji->type != cJSON_Array) { + //fprintf(stderr, "\"raw_crop\" must be an array\n"); + return false; + } + + int i; + + for (i = 0, ji = ji->child; i < 4 && ji != nullptr; i++, ji = ji->next) { + if (ji->type != cJSON_Number) { + //fprintf(stderr, "\"raw_crop\" array must contain numbers\n"); + return false; + } + + //cc->raw_crop[i] = ji->valueint; + rc[i] = ji->valueint; + } + + if (i != 4 || ji != nullptr) { + //fprintf(stderr, "\"raw_crop\" must contain 4 numbers\n"); + return false; + } + + cc->raw_crop[std::make_pair(w, h)] = rc; + return true; + }; + + const auto get_masked_areas = + [](int w, int h, const cJSON *ji, CameraConst *cc) -> bool + { + std::array, 2> rm; + + if (ji->type != cJSON_Array) { + //fprintf(stderr, "\"masked_areas\" must be an array\n"); + return false; + } + + int i; + + for (i = 0, ji = ji->child; i < 2 * 4 && ji != nullptr; i++, ji = ji->next) { + if (ji->type != cJSON_Number) { + //fprintf(stderr, "\"masked_areas\" array must contain numbers\n"); + return false; + } + + //cc->raw_mask[i / 4][i % 4] = ji->valueint; + rm[i / 4][i % 4] = ji->valueint; + } + + if (i % 4 != 0) { + //fprintf(stderr, "\"masked_areas\" array length must be divisable by 4\n"); + return false; + } + + cc->raw_mask[std::make_pair(w, h)] = rm; + return true; + }; + const cJSON *ji = cJSON_GetObjectItem(js, "dcraw_matrix"); if (ji) { @@ -216,24 +276,32 @@ CameraConst* CameraConst::parseEntry(const void *cJSON_, const char *make_model) if (ji) { if (ji->type != cJSON_Array) { - fprintf(stderr, "\"raw_crop\" must be an array\n"); + fprintf(stderr, "invalid entry for raw_crop.\n"); return nullptr; - } - - int i; - - for (i = 0, ji = ji->child; i < 4 && ji; i++, ji = ji->next) { - if (ji->type != cJSON_Number) { - fprintf(stderr, "\"raw_crop\" array must contain numbers\n"); - return nullptr; + } else if (!get_raw_crop(0, 0, ji, cc.get())) { + cJSON *je; + cJSON_ArrayForEach(je, ji) { + if (!cJSON_IsObject(je)) { + fprintf(stderr, "invalid entry for raw_crop.\n"); + return nullptr; + } else { + auto js = cJSON_GetObjectItem(je, "frame"); + if (!js || js->type != cJSON_Array || + cJSON_GetArraySize(js) != 2 || + !cJSON_IsNumber(cJSON_GetArrayItem(js, 0)) || + !cJSON_IsNumber(cJSON_GetArrayItem(js, 1))) { + fprintf(stderr, "invalid entry for raw_crop.\n"); + return nullptr; + } + int w = cJSON_GetArrayItem(js, 0)->valueint; + int h = cJSON_GetArrayItem(js, 1)->valueint; + js = cJSON_GetObjectItem(je, "crop"); + if (!js || !get_raw_crop(w, h, js, cc.get())) { + fprintf(stderr, "invalid entry for raw_crop.\n"); + return nullptr; + } + } } - - cc->raw_crop[i] = ji->valueint; - } - - if (i != 4 || ji) { - fprintf(stderr, "\"raw_crop\" must contain 4 numbers\n"); - return nullptr; } } @@ -241,24 +309,32 @@ CameraConst* CameraConst::parseEntry(const void *cJSON_, const char *make_model) if (ji) { if (ji->type != cJSON_Array) { - fprintf(stderr, "\"masked_areas\" must be an array\n"); + fprintf(stderr, "invalid entry for masked_areas.\n"); return nullptr; - } - - int i; - - for (i = 0, ji = ji->child; i < 2 * 4 && ji; i++, ji = ji->next) { - if (ji->type != cJSON_Number) { - fprintf(stderr, "\"masked_areas\" array must contain numbers\n"); - return nullptr; + } else if (!get_masked_areas(0, 0, ji, cc.get())) { + cJSON *je; + cJSON_ArrayForEach(je, ji) { + if (!cJSON_IsObject(je)) { + fprintf(stderr, "invalid entry for masked_areas.\n"); + return nullptr; + } else { + auto js = cJSON_GetObjectItem(je, "frame"); + if (!js || js->type != cJSON_Array || + cJSON_GetArraySize(js) != 2 || + !cJSON_IsNumber(cJSON_GetArrayItem(js, 0)) || + !cJSON_IsNumber(cJSON_GetArrayItem(js, 1))) { + fprintf(stderr, "invalid entry for masked_areas.\n"); + return nullptr; + } + int w = cJSON_GetArrayItem(js, 0)->valueint; + int h = cJSON_GetArrayItem(js, 1)->valueint; + js = cJSON_GetObjectItem(je, "areas"); + if (!js || !get_masked_areas(w, h, js, cc.get())) { + fprintf(stderr, "invalid entry for masked_areas.\n"); + return nullptr; + } + } } - - cc->raw_mask[i / 4][i % 4] = ji->valueint; - } - - if (i % 4 != 0) { - fprintf(stderr, "\"masked_areas\" array length must be divisible by 4\n"); - return nullptr; } } @@ -399,29 +475,41 @@ void CameraConst::update_pdafOffset(int other) pdafOffset = other; } -bool CameraConst::has_rawCrop() const + +bool CameraConst::has_rawCrop(int raw_width, int raw_height) const { - return raw_crop[0] != 0 || raw_crop[1] != 0 || raw_crop[2] != 0 || raw_crop[3] != 0; + return raw_crop.find(std::make_pair(raw_width, raw_height)) != raw_crop.end() || raw_crop.find(std::make_pair(0, 0)) != raw_crop.end(); } -void CameraConst::get_rawCrop(int& left_margin, int& top_margin, int& width, int& height) const + +void CameraConst::get_rawCrop(int raw_width, int raw_height, int &left_margin, int &top_margin, int &width, int &height) const { - left_margin = raw_crop[0]; - top_margin = raw_crop[1]; - width = raw_crop[2]; - height = raw_crop[3]; + auto it = raw_crop.find(std::make_pair(raw_width, raw_height)); + if (it == raw_crop.end()) { + it = raw_crop.find(std::make_pair(0, 0)); + } + if (it != raw_crop.end()) { + left_margin = it->second[0]; + top_margin = it->second[1]; + width = it->second[2]; + height = it->second[3]; + } else { + left_margin = top_margin = width = height = 0; + } } -bool CameraConst::has_rawMask(int idx) const + +bool CameraConst::has_rawMask(int raw_width, int raw_height, int idx) const { if (idx < 0 || idx > 1) { return false; } - return (raw_mask[idx][0] | raw_mask[idx][1] | raw_mask[idx][2] | raw_mask[idx][3]) != 0; + return raw_mask.find(std::make_pair(raw_width, raw_height)) != raw_mask.end() || raw_mask.find(std::make_pair(0, 0)) != raw_mask.end(); } -void CameraConst::get_rawMask(int idx, int& top, int& left, int& bottom, int& right) const + +void CameraConst::get_rawMask(int raw_width, int raw_height, int idx, int &top, int &left, int &bottom, int &right) const { top = left = bottom = right = 0; @@ -429,10 +517,17 @@ void CameraConst::get_rawMask(int idx, int& top, int& left, int& bottom, int& ri return; } - top = raw_mask[idx][0]; - left = raw_mask[idx][1]; - bottom = raw_mask[idx][2]; - right = raw_mask[idx][3]; + auto it = raw_mask.find(std::make_pair(raw_width, raw_height)); + if (it == raw_mask.end()) { + it = raw_mask.find(std::make_pair(0, 0)); + } + + if (it != raw_mask.end()) { + top = it->second[idx][0]; + left = it->second[idx][1]; + bottom = it->second[idx][2]; + right = it->second[idx][3]; + } } void CameraConst::update_Levels(const CameraConst *other) @@ -464,9 +559,7 @@ void CameraConst::update_Crop(CameraConst *other) return; } - if (other->has_rawCrop()) { - other->get_rawCrop(raw_crop[0], raw_crop[1], raw_crop[2], raw_crop[3]); - } + raw_crop.insert(other->raw_crop.begin(), other->raw_crop.end()); } bool CameraConst::get_Levels(camera_const_levels & lvl, int bw, int iso, float fnumber) const diff --git a/rtengine/camconst.h b/rtengine/camconst.h index aa0702439..273bdd7a1 100644 --- a/rtengine/camconst.h +++ b/rtengine/camconst.h @@ -1,9 +1,11 @@ -/* +/* -*- C++ -*- + * * This file is part of RawTherapee. */ #pragma once #include +#include #include #include @@ -17,17 +19,17 @@ class ustring; namespace rtengine { -struct camera_const_levels { - int levels[4]; -}; - class CameraConst final { private: + struct camera_const_levels { + int levels[4]; + }; + std::string make_model; short dcraw_matrix[12]; - int raw_crop[4]; - int raw_mask[2][4]; + std::map, std::array> raw_crop; + std::map, std::array, 2>> raw_mask; int white_max; std::map mLevels[2]; std::map mApertureScaling; @@ -47,10 +49,10 @@ public: const short *get_dcrawMatrix(void) const; const std::vector& get_pdafPattern() const; int get_pdafOffset() const {return pdafOffset;}; - bool has_rawCrop(void) const; - void get_rawCrop(int& left_margin, int& top_margin, int& width, int& height) const; - bool has_rawMask(int idx) const; - void get_rawMask(int idx, int& top, int& left, int& bottom, int& right) const; + bool has_rawCrop(int raw_width, int raw_height) const; + void get_rawCrop(int raw_width, int raw_height, int& left_margin, int& top_margin, int& width, int& height) const; + bool has_rawMask(int raw_width, int raw_height, int idx) const; + void get_rawMask(int raw_width, int raw_height, int idx, int& top, int& left, int& bottom, int& right) const; int get_BlackLevel(int idx, int iso_speed) const; int get_WhiteLevel(int idx, int iso_speed, float fnumber) const; bool has_globalGreenEquilibration() const; @@ -77,4 +79,5 @@ public: const CameraConst *get(const char make[], const char model[]) const; }; -} +} // namespace rtengine + diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 2b243e04a..ac3980bbe 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -70,6 +70,14 @@ Examples: // cropped so the "negative number" way is not totally safe. "raw_crop": [ 10, 20, 4000, 3000 ], + // multi-aspect support (added 2020-12-03) + // "frame" defines the full dimensions the crop applies to + // (with [0, 0] being the fallback crop if none of the other applies) + "raw_crop" : [ + { "frame" : [4100, 3050], "crop": [10, 20, 4050, 3020] }, + { "frame" : [0, 0], "crop": [10, 20, 4000, 3000] } + ] + // Almost same as MaskedAreas DNG tag, used for black level measuring. Here up to two areas can be defined // by tetrads of numbers: "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], @@ -84,6 +92,14 @@ Examples: // instead, to take care of possible light leaks from the light sensing area to the optically black (masked) // area or sensor imperfections at the outer borders. + // multi-aspect support (added 2020-12-03) + // "frame" defines the full dimensions the masked areas apply to + // (with [0, 0] being the fallback crop if none of the other applies) + "masked_areas" : [ + { "frame" : [4100, 3050], "areas": [10, 20, 4050, 3020] }, + { "frame" : [0, 0], "areas": [10, 20, 4000, 3000] } + ] + // list of indices of the rows with on-sensor PDAF pixels, for cameras that have such features. The indices here form a pattern that is repeated for the whole height of the sensor. The values are relative to the "pdaf_offset" value (see below) "pdaf_pattern" : [ 0,12,36,54,72,90,114,126,144,162,180,204,216,240,252,270,294,306,324,342,366,384,396,414,432,450,474,492,504,522,540,564,576,594,606,630 ], // index of the first row of the PDAF pattern in the sensor (0 is the topmost row). Allowed to be negative for convenience (this means that the first repetition of the pattern doesn't start from the first row) @@ -1210,33 +1226,50 @@ Camera constants: { // Quality C "make_model": "Canon EOS R3", - "dcraw_matrix" : [9423,-2839,-1195,-4532,12377,2415,-483,1374,5276] + "dcraw_matrix" : [ 9423, -2839, -1195, -4532, 12377, 2415, -483, 1374, 5276 ], + "raw_crop": [ 160, 120, 6024, 4024 ] }, { // Quality C "make_model": "Canon EOS R5", "dcraw_matrix" : [9766, -2953, -1254, -4276, 12116, 2433, -437, 1336, 5131], - "raw_crop" : [ 128, 96, 8224, 5490 ], - "masked_areas" : [ 94, 20, 5578, 122 ], + "raw_crop" : [ + { "frame" : [ 8352, 5586 ], "crop" : [ 128, 96, 8224, 5490 ] }, + { "frame" : [ 5248, 3510 ], "crop" : [ 128, 96, 5120, 3382 ] } + ], + "masked_areas" : [ + { "frame" : [ 8352, 5586 ], "areas": [ 94, 20, 5578, 122 ] }, + { "frame" : [ 5248, 3510 ], "areas": [ 94, 20, 3510, 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 ], + "raw_crop": [ + { "frame": [5568, 3708], "crop" : [ 72, 38, 5496, 3670 ] }, + { "frame": [3584, 2386], "crop" : [ 156, 108, 3404, 2270 ] } + ], + "masked_areas" : [ + { "frame": [5568, 3708], "areas": [ 40, 10, 5534, 70 ] }, + { "frame": [3584, 2386], "areas": [ 40, 10, 2374, 110 ] } + ], "ranges" : { "white" : 16382 } }, { // Quality C "make_model": "Canon EOS R7", - "dcraw_matrix" : [10424, -3138, -1300, -4221, 11938, 2584, -547, 1658, 6183] + "dcraw_matrix" : [10424, -3138, -1300, -4221, 11938, 2584, -547, 1658, 6183], + "raw_crop": [ 144, 72, 6984, 4660 ], + "masked_areas" : [ 70, 20, 4724, 138 ] }, { // Quality C "make_model": "Canon EOS R10", - "dcraw_matrix" : [9269, -2012, -1107, -3990, 11762, 2527, -569, 2093, 4913] + "dcraw_matrix" : [9269, -2012, -1107, -3990, 11762, 2527, -569, 2093, 4913], + "raw_crop": [ 144, 40, 6048, 4020 ], + "masked_areas" : [ 38, 20, 4052, 138 ] }, { // Quality C, CHDK DNGs, raw frame correction @@ -1377,7 +1410,11 @@ Camera constants: { // Quality C "make_model": [ "FUJIFILM GFX 100", "FUJIFILM GFX100S" ], "dcraw_matrix" : [ 16212, -8423, -1583, -4336, 12583, 1937, -195, 726, 6199 ], // taken from ART - "raw_crop": [ 0, 2, 11664, 8734 ] + "raw_crop": [ + // multi-aspect crop to account for 16-shot pixel shift images + { "frame" : [11808, 8754], "crop" : [ 0, 2, 11664, 8734 ] }, + { "frame" : [23616, 17508], "crop" : [ 0, 4, 23328, 17468 ] } + ] }, { // Quality B @@ -1543,6 +1580,18 @@ Camera constants: "ranges": { "white": 4040 } }, + { // Quality B + "make_model": [ "FUJIFILM X-T5", "FUJIFILM X-H2" ], + "dcraw_matrix": [ 11809, -5358, -1141, -4248, 12164, 2343, -514, 1097, 5848 ], // RawSpeed / DNG + "raw_crop": [ 0, 5, 7752, 5184 ] + }, + + { // Quality C + "make_model": "FUJIFILM DBP for GX680", + "dcraw_matrix": [ 12741, -4916, -1420, -8510, 16791, 1715, -1767, 2302, 7771 ], // same as S2Pro as per LibRaw + "ranges": { "white": 4096, "black": 132 } + }, + { // Quality C, Leica C-Lux names can differ? "make_model" : [ "LEICA C-LUX", "LEICA CAM-DC25" ], "dcraw_matrix" : [7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898] @@ -1924,6 +1973,11 @@ Camera constants: "dcraw_matrix" : [13705, -6004, -1401, -5464, 13568, 2062, -940, 1706, 7618] // DNG }, + { // Quality C + "make_model" : "NIKON Z 9", + "dcraw_matrix" : [13389, -6049, -1441, -4544, 12757, 1969, 229, 498, 7390] //DNG + }, + { // Quality C, only color matrix and PDAF lines info "make_model" : "Nikon Z 6", "dcraw_matrix" : [8210, -2534, -683, -5355, 13338, 2212, -1143, 1928, 6464], // DNG v13.2 @@ -2121,6 +2175,16 @@ Camera constants: "dcraw_matrix" : [8360, -2420, -880, -3928, 12353, 1739, -1381, 2416, 5173] // DNG }, + { // Quality C + "make_model": ["OM Digital Solutions OM-1"], + "ranges": { "white": 4095 }, + "raw_crop" : [ + { "frame" : [10400, 7792], "crop": [0, 0, 10390, 7792] }, + { "frame" : [8180, 6132], "crop": [0, 0, 8172, 6132] }, + { "frame" : [5220, 3912], "crop": [0, 0, 5220, 3912] } + ] + }, + { // Quality B "make_model": [ "Panasonic DC-LX100M2" ], "dcraw_matrix": [ 11577, -4230, -1106, -3967, 12211, 1957, -759, 1762, 5610 ], // DNG v13.2 @@ -2144,7 +2208,8 @@ Camera constants: { // Quality C "make_model": [ "Panasonic DC-G90", "Panasonic DC-G95", "Panasonic DC-G99" ], - "dcraw_matrix": [ 9657, -3963, -748, -3361, 11378, 2258, -568, 1414, 5158 ] // DNG + "dcraw_matrix": [ 9657, -3963, -748, -3361, 11378, 2258, -568, 1414, 5158 ], // DNG + "ranges": { "black": 15 } // see above: RT already reads a value from exif }, { // Quality C @@ -2981,7 +3046,10 @@ Camera constants: { // Quality B, correction for frame width "make_model": [ "Sony ILCE-7S", "Sony ILCE-7SM2" ], "dcraw_matrix": [ 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 ], // DNG_v9.2 D65 - "raw_crop": [ 0, 0, 4254, 2848 ], + "raw_crop" : [ + { "frame" : [ 2816, 1872 ], "crop" : [ 0, 0, 2792, 1872 ] }, + { "frame" : [ 4254, 2848 ], "crop" : [ 0, 0, 4254, 2848 ] } + ], "ranges": { "black": 512, "white": 16300 } }, diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index e3bd9c988..4c70ad951 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -57,7 +57,7 @@ bool loadFile( rtengine::procparams::ColorManagementParams icm; icm.workingProfile = working_color_space; - img_src.getImage(curr_wb, TR_NONE, img_float.get(), pp, rtengine::procparams::ToneCurveParams(), rtengine::procparams::RAWParams()); + img_src.getImage(curr_wb, TR_NONE, img_float.get(), pp, rtengine::procparams::ToneCurveParams(), rtengine::procparams::RAWParams(), 0); if (!working_color_space.empty()) { img_src.convertColorSpace(img_float.get(), icm, curr_wb); diff --git a/rtengine/color.cc b/rtengine/color.cc index d6c35208d..085fd41ce 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -24,6 +24,7 @@ #include "sleef.h" #include "opthelper.h" #include "iccstore.h" +#include using namespace std; @@ -1910,6 +1911,152 @@ void Color::Lch2Luv(float c, float h, float &u, float &v) v = c * sincosval.y; } +void Color::primaries_to_xyz(double p[6], double Wx, double Wz, double *pxyz) +{ + //calculate Xr, Xg, Xb, Yr, Yb, Tg, Zr,Zg Zb + double Wy = 1.0; + double Xr = p[0] / p[1]; + double Yr = 1.0; + double Zr = (1.0 - p[0] - p[1]) / p[1]; + double Xg = p[2] / p[3]; + double Yg = 1.0; + double Zg = (1.0 - p[2] - p[3]) / p[3]; + double Xb = p[4] / p[5]; + double Yb = 1.0; + double Zb = (1.0 - p[4] - p[5]) / p[5]; + + using Triple = std::array; + + using Matrix = std::array; + + Matrix input_prim; + Matrix inv_input_prim = {}; + input_prim[0][0] = Xr; + input_prim[0][1] = Yr; + input_prim[0][2] = Zr; + input_prim[1][0] = Xg; + input_prim[1][1] = Yg; + input_prim[1][2] = Zg; + input_prim[2][0] = Xb; + input_prim[2][1] = Yb; + input_prim[2][2] = Zb; + + //invert matrix + if (!rtengine::invertMatrix(input_prim, inv_input_prim)) { + std::cout << "Matrix is not invertible, skipping" << std::endl; + } + + //white point D50 used by LCMS + double Wdx = 0.96420; + double Wdy = 1.0; + double Wdz = 0.82490; + + double Sr = Wx * inv_input_prim [0][0] + Wy * inv_input_prim [1][0] + Wz * inv_input_prim [2][0]; + double Sg = Wx * inv_input_prim [0][1] + Wy * inv_input_prim [1][1] + Wz * inv_input_prim [2][1]; + double Sb = Wx * inv_input_prim [0][2] + Wy * inv_input_prim [1][2] + Wz * inv_input_prim [2][2]; + + //XYZ matrix for primaries and temp + Matrix mat_xyz = {}; + mat_xyz[0][0] = Sr * Xr; + mat_xyz[0][1] = Sr * Yr; + mat_xyz[0][2] = Sr * Zr; + mat_xyz[1][0] = Sg * Xg; + mat_xyz[1][1] = Sg * Yg; + mat_xyz[1][2] = Sg * Zg; + mat_xyz[2][0] = Sb * Xb; + mat_xyz[2][1] = Sb * Yb; + mat_xyz[2][2] = Sb * Zb; + + //chromatic adaptation Bradford + Matrix MaBradford = {}; + MaBradford[0][0] = 0.8951; + MaBradford[0][1] = -0.7502; + MaBradford[0][2] = 0.0389; + MaBradford[1][0] = 0.2664; + MaBradford[1][1] = 1.7135; + MaBradford[1][2] = -0.0685; + MaBradford[2][0] = -0.1614; + MaBradford[2][1] = 0.0367; + MaBradford[2][2] = 1.0296; + + Matrix Ma_oneBradford = {}; + Ma_oneBradford[0][0] = 0.9869929; + Ma_oneBradford[0][1] = 0.4323053; + Ma_oneBradford[0][2] = -0.0085287; + Ma_oneBradford[1][0] = -0.1470543; + Ma_oneBradford[1][1] = 0.5183603; + Ma_oneBradford[1][2] = 0.0400428; + Ma_oneBradford[2][0] = 0.1599627; + Ma_oneBradford[2][1] = 0.0492912; + Ma_oneBradford[2][2] = 0.9684867; + + //R G B source + double Rs = Wx * MaBradford[0][0] + Wy * MaBradford[1][0] + Wz * MaBradford[2][0]; + double Gs = Wx * MaBradford[0][1] + Wy * MaBradford[1][1] + Wz * MaBradford[2][1]; + double Bs = Wx * MaBradford[0][2] + Wy * MaBradford[1][2] + Wz * MaBradford[2][2]; + + // R G B destination + double Rd = Wdx * MaBradford[0][0] + Wdy * MaBradford[1][0] + Wdz * MaBradford[2][0]; + double Gd = Wdx * MaBradford[0][1] + Wdy * MaBradford[1][1] + Wdz * MaBradford[2][1]; + double Bd = Wdx * MaBradford[0][2] + Wdy * MaBradford[1][2] + Wdz * MaBradford[2][2]; + + //cone destination + Matrix cone_dest_sourc = {}; + cone_dest_sourc [0][0] = Rd / Rs; + cone_dest_sourc [0][1] = 0.; + cone_dest_sourc [0][2] = 0.; + cone_dest_sourc [1][0] = 0.; + cone_dest_sourc [1][1] = Gd / Gs; + cone_dest_sourc [1][2] = 0.; + cone_dest_sourc [2][0] = 0.; + cone_dest_sourc [2][1] = 0.; + cone_dest_sourc [2][2] = Bd / Bs; + + //cone dest + Matrix cone_ma_one = {}; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + cone_ma_one[i][j] = 0; + + for (int k = 0; k < 3; ++k) { + cone_ma_one[i][j] += cone_dest_sourc [i][k] * Ma_oneBradford[k][j]; + } + } + } + + //generate adaptation bradford matrix + Matrix adapt_chroma = {}; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + adapt_chroma [i][j] = 0; + + for (int k = 0; k < 3; ++k) { + adapt_chroma[i][j] += MaBradford[i][k] * cone_ma_one[k][j]; + } + } + } + + Matrix mat_xyz_brad = {}; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + mat_xyz_brad[i][j] = 0; + + for (int k = 0; k < 3; ++k) { + mat_xyz_brad[i][j] += mat_xyz[i][k] * adapt_chroma[k][j]; + } + } + } + + //push result in pxyz + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + pxyz[i * 3 + j] = mat_xyz_brad[i][j]; + } + } +} /* * Gamut mapping algorithm @@ -1931,13 +2078,19 @@ 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]) { - float u = 4 * X / (X + 15 * Y + 3 * Z) - u0; - float v = 9 * Y / (X + 15 * Y + 3 * Z) - v0; - + float epsil = 0.0001f; + float intermXYZ = X + 15 * Y + 3 * Z; + if(intermXYZ <= 0.f) { + intermXYZ = epsil; + } + + float u = 4 * X / (intermXYZ) - u0; + float v = 9 * Y / (intermXYZ) - v0; float lam[3][2]; - float lam_min = 1.0; + float lam_min = 1.0f; for (int c = 0; c < 3; c++) for (int m = 0; m < 2; m++) { @@ -1955,17 +2108,24 @@ void Color::gamutmap(float &X, float Y, float &Z, const double p[3][3]) p[0][c] * (5 * Y * p[1][c1] + m * 65535 * p[1][c1] * p[2][c2] + Y * p[2][c1] - m * 65535 * p[1][c2] * p[2][c1]) + m * 65535 * p[0][c2] * (p[1][c1] * p[2][c] - p[1][c] * p[2][c1]))); - if (lam[c][m] < lam_min && lam[c][m] > 0) { + if (lam[c][m] < lam_min && lam[c][m] > 0.f) { lam_min = lam[c][m]; } } - u = u * lam_min + u0; - v = v * lam_min + v0; + u = u * (double) lam_min + u0; + v = v * (double) lam_min + v0; X = (9 * u * Y) / (4 * v); - Z = (12 - 3 * u - 20 * v) * Y / (4 * v); + float intermuv = 12 - 3 * u - 20 * v; + if(intermuv < 0.f) { + intermuv = 0.f; + } + Z = (intermuv) * Y / (4 * v); + + + } void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s) diff --git a/rtengine/color.h b/rtengine/color.h index f602ade83..3622a9e36 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -1847,6 +1847,13 @@ static inline void Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, v */ static void gamutmap(float &X, float Y, float &Z, const double p[3][3]); + /** + * @brief Convert primaries in XYZ values in function of illuminant + * @param p primaries red, gree, blue + * @param Wx Wy white for illuminant + * @param pxyz return matrix XYZ + */ + static void primaries_to_xyz (double p[6], double Wx, double Wz, double *pxyz); /** * @brief Get HSV's hue from the Lab's hue diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index 36d42f063..f6e980f2a 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -33,7 +33,7 @@ namespace rtengine { -static const double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Desmis 2° Standard Observer. +static const color_match_type cie_colour_match_jd2 = {//350nm to 830nm 5 nm J.Desmis 2° Standard Observer. {0.0000000, 0.000000, 0.000000}, {0.0000000, 0.000000, 0.000000}, {0.0001299, 0.0003917, 0.0006061}, {0.0002321, 0.000006965, 0.001086}, {0.0004149, 0.00001239, 0.001946}, {0.0007416, 0.00002202, 0.003846}, {0.001368, 0.000039, 0.006450001}, {0.002236, 0.000064, 0.01054999}, {0.004243, 0.000120, 0.02005001}, @@ -70,7 +70,7 @@ static const double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Des }; -static double cie_colour_match_jd[97][3] = {//350nm to 830nm 5 nm J.Desmis 10° Standard Observer. +static const color_match_type cie_colour_match_jd = {//350nm to 830nm 5 nm J.Desmis 10° Standard Observer. {0.000000000000, 0.000000000000, 0.000000000000}, {0.000000000000, 0.000000000000, 0.000000000000}, {0.000000122200, 0.000000013398, 0.000000535027}, @@ -2963,15 +2963,16 @@ void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxy // We first test for specially handled methods const auto iterator = spectMap.find(method); + const auto &color_match = (settings->observer10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; if (iterator != spectMap.end()) { - spectrum_to_xyz_preset(iterator->second, x, y, z); + spectrum_to_xyz_preset(iterator->second, x, y, z, color_match); } else { // otherwise we use the Temp+Green generic solution if (temp <= INITIALBLACKBODY) { // if temperature is between 2000K and 4000K we use blackbody, because there will be no Daylight reference below 4000K... // of course, the previous version of RT used the "magical" but wrong formula of U.Fuchs (Ufraw). - spectrum_to_xyz_blackbody(temp, x, y, z); + spectrum_to_xyz_blackbody(temp, x, y, z, color_match); } else { // from 4000K up to 25000K: using the D illuminant (daylight) which is standard double x_D, y_D; @@ -2990,7 +2991,7 @@ void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxy double interm = 0.0241 + 0.2562 * x_D - 0.734 * y_D; double m1 = (-1.3515 - 1.7703 * x_D + 5.9114 * y_D) / interm; double m2 = (0.03 - 31.4424 * x_D + 30.0717 * y_D) / interm; - spectrum_to_xyz_daylight(m1, m2, x, y, z); + spectrum_to_xyz_daylight(m1, m2, x, y, z, color_match); } } @@ -3169,17 +3170,19 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul, float CRI_RT = 0.0, CRI[50]; float CRI_RTs = 0.0, CRIs[8]; + const auto &color_match = (settings->observer10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; + for(int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_preset(spec_color[i], spect_illum[illum + 3], XchkLamp[i], YchkLamp[i], ZchkLamp[i]); + spectrum_to_color_xyz_preset(spec_color[i], spect_illum[illum + 3], XchkLamp[i], YchkLamp[i], ZchkLamp[i], color_match); } //calculate XYZ for each color : for Blackbody and Daylight at tempw if(tempw <= INITIALBLACKBODY) { for(int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_blackbody(spec_color[i], tempw, Xchk[i], Ychk[i], Zchk[i]); + spectrum_to_color_xyz_blackbody(spec_color[i], tempw, Xchk[i], Ychk[i], Zchk[i], color_match); } - spectrum_to_xyz_blackbody(tempw, x, y, z);//for white point + spectrum_to_xyz_blackbody(tempw, x, y, z, color_match);//for white point } else { // after 6600K (arbitrary) I use daylight...because ...but there is no lamp... double m11, m22, x_DD, y_DD, interm2; @@ -3197,10 +3200,10 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul, m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2; for(int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_daylight(spec_color[i], m11, m22, Xchk[i], Ychk[i], Zchk[i]); + spectrum_to_color_xyz_daylight(spec_color[i], m11, m22, Xchk[i], Ychk[i], Zchk[i], color_match); } - spectrum_to_xyz_daylight(m11, m22, x, y, z); + spectrum_to_xyz_daylight(m11, m22, x, y, z, color_match); } if (settings->verbose) { @@ -3388,22 +3391,22 @@ The next 3 methods are inspired from: this values are often called xBar yBar zBar and are characteristics of a color / illuminant -values cie_colour_match[][3] = 2° Standard Observer x2, y2, z2 +values cie_colour_match2[][3] = 2° Standard Observer x2, y2, z2 E.g. for 380nm: x2=0.001368 y2=0.000039 z2=0.006451 round in J.Walker to 0.0014 0.0000 0.0065 above I have increase precision used by J.Walker and pass to 350nm to 830nm And also add 10° standard observer */ -void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, double &y, double &z) +void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, double &y, double &z, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0, XYZ; for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = daylight_spect(lambda, _m1, _m2); - X += Me * cie_colour_match_jd[i][0]; - Y += Me * cie_colour_match_jd[i][1]; - Z += Me * cie_colour_match_jd[i][2]; + X += Me * color_match[i][0]; + Y += Me * color_match[i][1]; + Z += Me * color_match[i][2]; } XYZ = (X + Y + Z); @@ -3412,16 +3415,16 @@ void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, doub z = Z / XYZ; } -void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, double &z) +void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, double &z, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0, XYZ; for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = blackbody_spect(lambda, _temp); - X += Me * cie_colour_match_jd[i][0]; - Y += Me * cie_colour_match_jd[i][1]; - Z += Me * cie_colour_match_jd[i][2]; + X += Me * color_match[i][0]; + Y += Me * color_match[i][1]; + Z += Me * color_match[i][2]; } XYZ = (X + Y + Z); @@ -3430,7 +3433,7 @@ void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, do z = Z / XYZ; } -void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, double &y, double &z) +void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, double &y, double &z, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0, XYZ; @@ -3447,16 +3450,16 @@ void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, dou this values are often called xBar yBar zBar and are characteristics of a color / illuminant - values cie_colour_match[][3] = 2° Standard Observer x2, y2, z2 + values cie_colour_match_jd2[][3] = 2° Standard Observer x2, y2, z2 E.g. for 380nm: x2=0.001368 y2=0.000039 z2=0.006451 round in J.Walker to 0.0014 0.0000 0.0065 above I have increased the precision used by J.Walker and pass from 350nm to 830nm And also add standard observer 10° */ for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = get_spectral_color(lambda, spec_intens); - X += Me * cie_colour_match_jd[i][0]; - Y += Me * cie_colour_match_jd[i][1]; - Z += Me * cie_colour_match_jd[i][2]; + X += Me * color_match[i][0]; + Y += Me * color_match[i][1]; + Z += Me * color_match[i][2]; } XYZ = (X + Y + Z); @@ -3466,7 +3469,7 @@ void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, dou } //calculate XYZ from spectrum data (color) and illuminant : J.Desmis December 2011 -void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz) +void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0, Yo = 0; @@ -3478,9 +3481,9 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou Me = get_spectral_color(lambda, spec_color); Mc = get_spectral_color(lambda, spec_intens); - X += Mc * cie_colour_match_jd[i][0] * Me; - Y += Mc * cie_colour_match_jd[i][1] * Me; - Z += Mc * cie_colour_match_jd[i][2] * Me; + X += Mc * color_match[i][0] * Me; + Y += Mc * color_match[i][1] * Me; + Z += Mc * color_match[i][2] * Me; } for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) { @@ -3488,7 +3491,7 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou double Ms; Ms = get_spectral_color(lambda, spec_intens); - Yo += cie_colour_match_jd[i][1] * Ms; + Yo += color_match[i][1] * Ms; } xx = X / Yo; @@ -3497,7 +3500,7 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou } //calculate XYZ from spectrum data (color) and illuminant : J.Desmis december 2011 -void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz) +void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0; @@ -3505,9 +3508,9 @@ void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) { const double Me = spec_color[i]; const double Mc = daylight_spect(lambda, _m1, _m2); - X += Mc * cie_colour_match_jd[i][0] * Me; - Y += Mc * cie_colour_match_jd[i][1] * Me; - Z += Mc * cie_colour_match_jd[i][2] * Me; + X += Mc * color_match[i][0] * Me; + Y += Mc * color_match[i][1] * Me; + Z += Mc * color_match[i][2] * Me; } xx = X / Y; @@ -3516,7 +3519,7 @@ void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double } //calculate XYZ from spectrum data (color) and illuminant : J.Desmis december 2011 -void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double _temp, double &xx, double &yy, double &zz) +void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double _temp, double &xx, double &yy, double &zz, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0; @@ -3524,9 +3527,9 @@ void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) { const double Me = spec_color[i]; const double Mc = blackbody_spect(lambda, _temp); - X += Mc * cie_colour_match_jd[i][0] * Me; - Y += Mc * cie_colour_match_jd[i][1] * Me; - Z += Mc * cie_colour_match_jd[i][2] * Me; + X += Mc * color_match[i][0] * Me; + Y += Mc * color_match[i][1] * Me; + Z += Mc * color_match[i][2] * Me; } xx = X / Y; @@ -3761,28 +3764,24 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float Refxyz[i].Zref = 0.f; } - if (settings->verbose) { - if (settings->itcwb_stdobserver10 == false) { +/* if (settings->verbose) { + + if (settings->itcwb_stdobserver10 == false) {//I will try to change settings by main printf("Use standard observer 2°\n"); } else { printf("Use standard observer 10°\n"); } - } - - if (settings->itcwb_stdobserver10 == false) { - for (int i = 0; i < 97; i++) { - cie_colour_match_jd[i][0] = cie_colour_match_jd2[i][0]; - cie_colour_match_jd[i][1] = cie_colour_match_jd2[i][1];; - cie_colour_match_jd[i][2] = cie_colour_match_jd2[i][2]; } - } +*/ + const color_match_type &color_match = (settings->observer10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; + // const color_match_type &color_match = (settings->itcwb_stdobserver10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; if (separated) { const double tempw = Txyz[repref].Tem; if (tempw <= INITIALBLACKBODY) { for (int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, TX[i], TY[i], TZ[i]); + spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, TX[i], TY[i], TZ[i], color_match); } } else { double m11, m22, x_DD, y_DD, interm2; @@ -3801,7 +3800,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2; for (int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, TX[i], TY[i], TZ[i]); + spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, TX[i], TY[i], TZ[i], color_match); } } } else { @@ -3810,7 +3809,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float if (tempw <= INITIALBLACKBODY) { for (int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref); + spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref, color_match); } } else { double x_DD; @@ -3829,7 +3828,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float const double m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2; for (int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref); + spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref, color_match); } } diff --git a/rtengine/colortemp.h b/rtengine/colortemp.h index 89c324490..78091f51d 100644 --- a/rtengine/colortemp.h +++ b/rtengine/colortemp.h @@ -26,6 +26,8 @@ namespace rtengine { +using color_match_type = double [97][3]; + constexpr double MINTEMP = 1500.0; constexpr double MAXTEMP = 60000.0; constexpr double MINGREEN = 0.02; @@ -375,13 +377,13 @@ public: static const double JDC468_greym13_325_spect[97]; static const double JDC468_greyf26_156_spect[97]; */ - static void spectrum_to_xyz_daylight (double _m1, double _m2, double &x, double &y, double &z); - static void spectrum_to_xyz_blackbody (double _temp, double &x, double &y, double &z); - static void spectrum_to_xyz_preset (const double* spec_intens, double &x, double &y, double &z); + static void spectrum_to_xyz_daylight (double _m1, double _m2, double &x, double &y, double &z, const color_match_type &color_match); + static void spectrum_to_xyz_blackbody (double _temp, double &x, double &y, double &z, const color_match_type &color_match); + static void spectrum_to_xyz_preset (const double* spec_intens, double &x, double &y, double &z, const color_match_type &color_match); - static void spectrum_to_color_xyz_daylight (const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz); - static void spectrum_to_color_xyz_blackbody (const double* spec_color, double _temp, double &xx, double &yy, double &zz); - static void spectrum_to_color_xyz_preset (const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz); + static void spectrum_to_color_xyz_daylight (const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz, const color_match_type &color_match); + static void spectrum_to_color_xyz_blackbody (const double* spec_color, double _temp, double &xx, double &yy, double &zz, const color_match_type &color_match); + static void spectrum_to_color_xyz_preset (const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz, const color_match_type &color_match); }; } diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index a42b377d4..7a2a5b4d5 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -2464,6 +2464,30 @@ void CLASS unpacked_load_raw() } } +// RT - from LibRaw +void CLASS unpacked_load_raw_FujiDBP() +/* +for Fuji DBP for GX680, aka DX-2000 + DBP_tile_width = 688; + DBP_tile_height = 3856; + DBP_n_tiles = 8; +*/ +{ + int scan_line, tile_n; + int nTiles = 8; + tile_width = raw_width / nTiles; + ushort *tile; + tile = (ushort *) calloc(raw_height, tile_width * 2); + for (tile_n = 0; tile_n < nTiles; tile_n++) { + read_shorts(tile, tile_width * raw_height); + for (scan_line = 0; scan_line < raw_height; scan_line++) { + memcpy(&raw_image[scan_line * raw_width + tile_n * tile_width], + &tile[scan_line * tile_width], tile_width * 2); + } + } + free(tile); + fseek(ifp, -2, SEEK_CUR); // avoid EOF error +} // RT void CLASS sony_arq_load_raw() @@ -5522,9 +5546,11 @@ void CLASS parse_makernote (int base, int uptag) offset = get4(); fseek (ifp, offset-8, SEEK_CUR); } else if (!strcmp (buf,"OLYMPUS") || - !strcmp (buf,"PENTAX ")) { + !strcmp (buf,"PENTAX ") || + !strncmp(buf,"OM SYS",6)) { // From LibRaw base = ftell(ifp)-10; fseek (ifp, -2, SEEK_CUR); + if (buf[1] == 'M') get4(); // From LibRaw order = get2(); if (buf[0] == 'O') get2(); } else if (!strncmp (buf,"SONY",4) || @@ -6319,12 +6345,13 @@ void CLASS parse_mos (int offset) void CLASS linear_table (unsigned len) { - int i; - if (len > 0x1000) len = 0x1000; - read_shorts (curve, len); - for (i=len; i < 0x1000; i++) - curve[i] = curve[i-1]; - maximum = curve[0xfff]; + const unsigned maxLen = std::min(0x10000ull, 1ull << tiff_bps); + len = std::min(len, maxLen); + read_shorts(curve, len); + maximum = curve[len - 1]; + for (std::size_t i = len; i < maxLen; ++i) { + curve[i] = maximum; + } } void CLASS parse_kodak_ifd (int base) @@ -6913,7 +6940,6 @@ it under the terms of the one of two licenses as you choose: unsigned oldOrder = order; order = 0x4d4d; // always big endian per definition in https://www.adobe.com/content/dam/acom/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf chapter 7 unsigned ntags = get4(); // read the number of opcodes - if (ntags < ifp->size / 12) { // rough check for wrong value (happens for example with DNG files from DJI FC6310) while (ntags-- && !ifp->eof) { unsigned opcode = get4(); @@ -6932,8 +6958,48 @@ it under the terms of the one of two licenses as you choose: break; } case 51009: /* OpcodeList2 */ - meta_offset = ftell(ifp); - break; + { + meta_offset = ftell(ifp); + const unsigned oldOrder = order; + order = 0x4d4d; // always big endian per definition in https://www.adobe.com/content/dam/acom/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf chapter 7 + unsigned ntags = get4(); // read the number of opcodes + if (ntags < ifp->size / 12) { // rough check for wrong value (happens for example with DNG files from DJI FC6310) + while (ntags-- && !ifp->eof) { + unsigned opcode = get4(); + if (opcode == 9 && gainMaps.size() < 4) { + fseek(ifp, 4, SEEK_CUR); // skip 4 bytes as we know that the opcode 4 takes 4 byte + fseek(ifp, 8, SEEK_CUR); // skip 8 bytes as they don't interest us currently + GainMap gainMap; + gainMap.Top = get4(); + gainMap.Left = get4(); + gainMap.Bottom = get4(); + gainMap.Right = get4(); + gainMap.Plane = get4(); + gainMap.Planes = get4(); + gainMap.RowPitch = get4(); + gainMap.ColPitch = get4(); + gainMap.MapPointsV = get4(); + gainMap.MapPointsH = get4(); + gainMap.MapSpacingV = getreal(12); + gainMap.MapSpacingH = getreal(12); + gainMap.MapOriginV = getreal(12); + gainMap.MapOriginH = getreal(12); + gainMap.MapPlanes = get4(); + const std::size_t n = static_cast(gainMap.MapPointsV) * static_cast(gainMap.MapPointsH) * static_cast(gainMap.MapPlanes); + gainMap.MapGain.reserve(n); + for (std::size_t i = 0; i < n; ++i) { + gainMap.MapGain.push_back(getreal(11)); + } + gainMaps.push_back(std::move(gainMap)); + } else { + fseek(ifp, 8, SEEK_CUR); // skip 8 bytes as they don't interest us currently + fseek(ifp, get4(), SEEK_CUR); + } + } + } + order = oldOrder; + break; + } case 64772: /* Kodak P-series */ if (len < 13) break; fseek (ifp, 16, SEEK_CUR); @@ -7108,7 +7174,7 @@ void CLASS apply_tiff() if (tiff_ifd[raw].bytes*4 == raw_width*raw_height*7) break; load_flags = 0; case 16: load_raw = &CLASS unpacked_load_raw; - if (!strncmp(make,"OLYMPUS",7) && + if ((!strncmp(make,"OLYMPUS",7) || !strncmp(make, "OM Digi", 7)) && // OM Digi from LibRaw tiff_ifd[raw].bytes*7 > raw_width*raw_height) load_raw = &CLASS olympus_load_raw; // ------- RT ------- @@ -8640,6 +8706,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 10901,-4095,-1074,-1141,9208,2293,-62,1417,5158 } }, { "Olympus XZ-2", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, + { "OM Digital Solutions OM-1", 0, 0, + { 9488, -3984, -714, -2887, 10945, 2229, -137, 960, 5786 } }, // From LibRaw { "OmniVision", 0, 0, /* DJC */ { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, { "Pentax *ist DL2", 0, 0, @@ -10066,6 +10134,9 @@ canon_a5: } else if (!strcmp(model, "X-Pro3") || !strcmp(model, "X-T3") || !strcmp(model, "X-T30") || !strcmp(model, "X-T4") || !strcmp(model, "X100V") || !strcmp(model, "X-S10")) { width = raw_width = 6384; height = raw_height = 4182; + } else if (!strcmp(model, "DBP for GX680")) { // Special case for #4204 + width = raw_width = 5504; + height = raw_height = 3856; } top_margin = (raw_height - height) >> 2 << 1; left_margin = (raw_width - width ) >> 2 << 1; @@ -10073,6 +10144,16 @@ canon_a5: if (width == 4032 || width == 4952 || width == 6032 || width == 8280) left_margin = 0; if (width == 3328 && (width -= 66)) left_margin = 34; if (width == 4936) left_margin = 4; + if (width == 5504) { // #4204, taken from LibRaw + left_margin = 32; + top_margin = 8; + width = raw_width - 2*left_margin; + height = raw_height - 2*top_margin; + load_raw = &CLASS unpacked_load_raw_FujiDBP; + filters = 0x16161616; + load_flags = 0; + flip = 6; + } if (!strcmp(model,"HS50EXR") || !strcmp(model,"F900EXR")) { width += 2; @@ -11041,6 +11122,70 @@ void CLASS nikon_14bit_load_raw() free(buf); } +bool CLASS isGainMapSupported() const { + if (!(dng_version && isBayer())) { + return false; + } + const auto n = gainMaps.size(); + if (n != 4) { // we need 4 gainmaps for bayer files + if (rtengine::settings->verbose) { + std::cout << "GainMap has " << n << " maps, but 4 are needed" << std::endl; + } + return false; + } + unsigned int check = 0; + bool noOp = true; + for (const auto &m : gainMaps) { + if (m.MapGain.size() < 1) { + if (rtengine::settings->verbose) { + std::cout << "GainMap has invalid size of " << m.MapGain.size() << std::endl; + } + return false; + } + if (m.MapGain.size() != static_cast(m.MapPointsV) * static_cast(m.MapPointsH) * static_cast(m.MapPlanes)) { + if (rtengine::settings->verbose) { + std::cout << "GainMap has size of " << m.MapGain.size() << ", but needs " << m.MapPointsV * m.MapPointsH * m.MapPlanes << std::endl; + } + return false; + } + if (m.RowPitch != 2 || m.ColPitch != 2) { + if (rtengine::settings->verbose) { + std::cout << "GainMap needs Row/ColPitch of 2/2, but has " << m.RowPitch << "/" << m.ColPitch << std::endl; + } + return false; + } + if (m.Top == 0){ + if (m.Left == 0) { + check += 1; + } else if (m.Left == 1) { + check += 2; + } + } else if (m.Top == 1) { + if (m.Left == 0) { + check += 4; + } else if (m.Left == 1) { + check += 8; + } + } + for (size_t i = 0; noOp && i < m.MapGain.size(); ++i) { + if (m.MapGain[i] != 1.f) { // we have at least one value != 1.f => map is not a nop + noOp = false; + } + } + } + if (noOp || check != 15) { // all maps are nops or the structure of the combination of 4 maps is not correct + if (rtengine::settings->verbose) { + if (noOp) { + std::cout << "GainMap is a nop" << std::endl; + } else { + std::cout << "GainMap has unsupported type : " << check << std::endl; + } + } + return false; + } + return true; +} + /* RT: Delete from here */ /*RT*/#undef SQR /*RT*/#undef MAX diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 849012cb7..aadc0b969 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -19,9 +19,13 @@ #pragma once +#include +#include + #include "myfile.h" #include - +#include "dnggainmap.h" +#include "settings.h" class DCraw { @@ -165,6 +169,8 @@ protected: PanasonicRW2Info(): bpp(0), encoding(0) {} }; PanasonicRW2Info RT_pana_info; + std::vector gainMaps; + public: struct CanonCR3Data { // contents of tag CMP1 for relevant track in CR3 file @@ -193,6 +199,18 @@ public: int crx_track_selected; short CR3_CTMDtag; }; + + bool isBayer() const + { + return (filters != 0 && filters != 9); + } + + const std::vector& getGainMaps() const { + return gainMaps; + } + + bool isGainMapSupported() const; + struct CanonLevelsData { unsigned cblack[4]; unsigned white; @@ -200,6 +218,7 @@ public: bool white_ok; CanonLevelsData(): cblack{0}, white{0}, black_ok(false), white_ok(false) {} }; + protected: CanonCR3Data RT_canon_CR3_data; @@ -432,6 +451,7 @@ void parse_hasselblad_gain(); void hasselblad_load_raw(); void leaf_hdr_load_raw(); void unpacked_load_raw(); +void unpacked_load_raw_FujiDBP(); void sinar_4shot_load_raw(); void imacon_full_load_raw(); void packed_load_raw(); diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index f4ac49fc4..8ddaa5f75 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -228,18 +228,18 @@ void Crop::update(int todo) if (settings->leveldnautsimpl == 1) { if (params.dirpyrDenoise.Cmethod == "MAN" || params.dirpyrDenoise.Cmethod == "PON") { PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); } } else { if (params.dirpyrDenoise.C2method == "MANU") { PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); } } if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PRE") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "PREV")) { PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); if ((!isDetailWindow) && parent->adnListener && skip == 1 && params.dirpyrDenoise.enabled) { float lowdenoise = 1.f; @@ -451,7 +451,7 @@ void Crop::update(int todo) for (int wcr = 0; wcr <= 2; wcr++) { for (int hcr = 0; hcr <= 2; hcr++) { PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1); - parent->imgsrc->getImage(parent->currWB, tr, origCropPart, ppP, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0); // we only need image reduced to 1/4 here for (int ii = 0; ii < crH; ii += 2) { @@ -613,7 +613,7 @@ void Crop::update(int todo) // if (params.dirpyrDenoise.Cmethod=="AUT" || params.dirpyrDenoise.Cmethod=="PON") {//reinit origCrop after Auto if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { //reinit origCrop after Auto PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); } if ((todo & M_SPOT) && params.spot.enabled && !params.spot.entries.empty()) { @@ -749,7 +749,7 @@ void Crop::update(int todo) fattalCrop.reset(f); PreviewProps pp(0, 0, parent->fw, parent->fh, skip); int tr = getCoarseBitMask(params.coarse); - parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw, 0); parent->imgsrc->convertColorSpace(f, params.icm, parent->currWB); if (params.dirpyrDenoise.enabled || params.filmNegative.enabled || params.spot.enabled) { diff --git a/rtengine/dnggainmap.h b/rtengine/dnggainmap.h new file mode 100644 index 000000000..25a01fd0f --- /dev/null +++ b/rtengine/dnggainmap.h @@ -0,0 +1,43 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 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 + * 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 + +struct GainMap +{ + std::uint32_t Top; + std::uint32_t Left; + std::uint32_t Bottom; + std::uint32_t Right; + std::uint32_t Plane; + std::uint32_t Planes; + std::uint32_t RowPitch; + std::uint32_t ColPitch; + std::uint32_t MapPointsV; + std::uint32_t MapPointsH; + double MapSpacingV; + double MapSpacingH; + double MapOriginV; + double MapOriginH; + std::uint32_t MapPlanes; + std::vector MapGain; +}; diff --git a/rtengine/dynamicprofile.cc b/rtengine/dynamicprofile.cc index 28516a1ee..6dbd2d0f0 100644 --- a/rtengine/dynamicprofile.cc +++ b/rtengine/dynamicprofile.cc @@ -77,7 +77,7 @@ bool DynamicProfileRule::operator< (const DynamicProfileRule &other) const } -bool DynamicProfileRule::matches (const rtengine::FramesMetaData *im) const +bool DynamicProfileRule::matches (const rtengine::FramesMetaData *im, const Glib::ustring& filename) const { return (iso (im->getISOSpeed()) && fnumber (im->getFNumber()) @@ -86,6 +86,7 @@ bool DynamicProfileRule::matches (const rtengine::FramesMetaData *im) const && expcomp (im->getExpComp()) && camera (im->getCamera()) && lens (im->getLens()) + && path (filename) && imagetype(im->getImageType(0))); } @@ -214,6 +215,7 @@ bool DynamicProfileRules::loadRules() get_double_range (rule.expcomp, kf, group, "expcomp"); get_optional (rule.camera, kf, group, "camera"); get_optional (rule.lens, kf, group, "lens"); + get_optional (rule.path, kf, group, "path"); get_optional (rule.imagetype, kf, group, "imagetype"); try { @@ -247,6 +249,7 @@ bool DynamicProfileRules::storeRules() set_double_range (kf, group, "expcomp", rule.expcomp); set_optional (kf, group, "camera", rule.camera); set_optional (kf, group, "lens", rule.lens); + set_optional (kf, group, "path", rule.path); set_optional (kf, group, "imagetype", rule.imagetype); kf.set_string (group, "profilepath", rule.profilepath); } diff --git a/rtengine/dynamicprofile.h b/rtengine/dynamicprofile.h index d91b91aee..654db3a8e 100644 --- a/rtengine/dynamicprofile.h +++ b/rtengine/dynamicprofile.h @@ -51,7 +51,7 @@ public: }; DynamicProfileRule(); - bool matches (const rtengine::FramesMetaData *im) const; + bool matches (const rtengine::FramesMetaData *im, const Glib::ustring& filename) const; bool operator< (const DynamicProfileRule &other) const; int serial_number; @@ -62,6 +62,7 @@ public: Range expcomp; Optional camera; Optional lens; + Optional path; Optional imagetype; Glib::ustring profilepath; }; diff --git a/rtengine/filmnegativeproc.cc b/rtengine/filmnegativeproc.cc index ae1813db9..c33dc4a9a 100644 --- a/rtengine/filmnegativeproc.cc +++ b/rtengine/filmnegativeproc.cc @@ -84,7 +84,7 @@ void getSpotAvgMax(ImageSource *imgsrc, ColorTemp currWB, const std::unique_ptr< } rtengine::Imagefloat spotImg(spotSize, spotSize); - imgsrc->getImage(currWB, tr, &spotImg, pp, params->toneCurve, params->raw); + imgsrc->getImage(currWB, tr, &spotImg, pp, params->toneCurve, params->raw, 0); auto avgMax = [spotSize, &spotImg](RGB & avg, RGB & max) -> void { avg = {}; diff --git a/rtengine/hilite_recon.cc b/rtengine/hilite_recon.cc index a45e5d345..f573ff015 100644 --- a/rtengine/hilite_recon.cc +++ b/rtengine/hilite_recon.cc @@ -32,14 +32,15 @@ #include "opthelper.h" #include "rawimagesource.h" #include "rt_math.h" -//#define BENCHMARK -//#include "StopWatch.h" +#define BENCHMARK +#include "StopWatch.h" #include "guidedfilter.h" #include "settings.h" #include "gauss.h" #include "rescale.h" #include "iccstore.h" #include "color.h" +#include "linalgebra.h" namespace { @@ -301,7 +302,7 @@ using namespace procparams; void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue, int blur) { - // BENCHFUN + //BENCHFUN double progress = 0.0; if (plistener) { @@ -1226,5 +1227,371 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue }// end of HLReconstruction + +//----------------------------------------------------------------------------- +// "inpaint opposed" algorithm taken from darktable +// +// (Very effective, very simple, very neat) +// +// Kudos to the original authors (@jenshannoschwalm from dt, in collaboration +// with @garagecoder and @Iain from gmic). +// +// Copyright and description of the original code follows +// +/* + Copyright (C) 2022 darktable developers. + + 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 . +*/ + +/* The refavg values are calculated in raw-RGB-cube3 space + We calculate all color channels in the 3x3 photosite area, this can be understaood as a "superpixel", + the "asking" location is in the centre. + As this works for bayer and xtrans sensors we don't have a fixed ratio but calculate the average + for every color channel first. + refavg for one of red, green or blue is defined as means of both other color channels (opposing). + + The basic idea / observation for the _process_opposed algorithm is, the refavg is a good estimate + for any clipped color channel in the vast majority of images, working mostly fine both for small specular + highlighted spots and large areas. + + The correction via some sort of global chrominance further helps to correct color casts. + The chrominace data are taken from the areas morphologically very close to clipped data. + Failures of the algorithm (color casts) are in most cases related to + a) very large differences between optimal white balance coefficients vs what we have as D65 in the darktable pipeline + b) complicated lightings so the gradients are not well related + c) a wrong whitepoint setting in the rawprepare module. + d) the maths might not be best +*/ +//----------------------------------------------------------------------------- + +namespace { + +constexpr int HL_BORDER = 8; +constexpr float HL_POWERF = 3.0f; + +// void border_fill_zero(int *d, int width, int height) +// { +// for (int i = 0; i < HL_BORDER * width; i++) { +// d[i] = 0; +// } +// for (int i = (height - HL_BORDER - 1) * width; i < width*height; i++) { +// d[i] = 0; +// } +// for (int row = HL_BORDER; row < height - HL_BORDER; row++) { +// int *p1 = d + row*width; +// int *p2 = d + (row+1)*width - HL_BORDER; +// for(int i = 0; i < HL_BORDER; i++) { +// p1[i] = p2[i] = 0; +// } +// } +// } + + +int test_dilate(const int *img, int i, int w1) +{ + int retval = 0; + retval = img[i-w1-1] | img[i-w1] | img[i-w1+1] | + img[i-1] | img[i] | img[i+1] | + img[i+w1-1] | img[i+w1] | img[i+w1+1]; + if (retval) { + return retval; + } + + const size_t w2 = 2*w1; + retval = img[i-w2-1] | img[i-w2] | img[i-w2+1] | + img[i-w1-2] | img[i-w1+2] | + img[i-2] | img[i+2] | + img[i+w1-2] | img[i+w1+2] | + img[i+w2-1] | img[i+w2] | img[i+w2+1]; + if (retval) { + return retval; + } + + const size_t w3 = 3*w1; + retval = img[i-w3-2] | img[i-w3-1] | img[i-w3] | img[i-w3+1] | img[i-w3+2] | + img[i-w2-3] | img[i-w2-2] | img[i-w2+2] | img[i-w2+3] | + img[i-w1-3] | img[i-w1+3] | + img[i-3] | img[i+3] | + img[i+w1-3] | img[i+w1+3] | + img[i+w2-3] | img[i+w2-2] | img[i+w2+2] | img[i+w2+3] | + img[i+w3-2] | img[i+w3-1] | img[i+w3] | img[i+w3+1] | img[i+w3+2]; + return retval; +} + + +void dilating(const int *img, int *o, int w1, int height) +{ +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int row = HL_BORDER; row < height - HL_BORDER; row++) { + for (int col = HL_BORDER, i = row*w1 + col; col < w1 - HL_BORDER; col++, i++) { + o[i] = test_dilate(img, i, w1); + } + } +} + +} // namespace + +void RawImageSource::highlight_recovery_opposed(float scale_mul[3], const ColorTemp &wb, float gainth) +{ + //BENCHFUN + + if (settings->verbose) { + std::cout << "Applying Highlight Recovery: Inpaint opposed" << std::endl; + } + + if (plistener) { + plistener->setProgressStr("PROGRESSBAR_HLREC"); + plistener->setProgress(0); + } + + double rr, gg, bb; + wb.getMultipliers(rr, gg, bb); + wbMul2Camera(rr, gg, bb); + + float gain = 1.2f * gainth; + + float clipval = 0.987f / gain; + const float scalecoeffs[3] = { + scale_mul[0] * float(rr) / 65535.f, + scale_mul[1] * float(gg) / 65535.f, + scale_mul[2] * float(bb) / 65535.f, + }; + const float clips[3] = { + clipval * float(rr), + clipval * float(gg), + clipval * float(bb) + }; + const float clipdark[3] = { + 0.03f * clips[0], + 0.125f * clips[1], + 0.03f * clips[2] + }; + + bool anyclipped = false; + float **chan[3] = { red, green, blue }; + + const float clipscale[3] = { + clips[0] / scalecoeffs[0], + clips[1] / scalecoeffs[1], + clips[2] / scalecoeffs[2] + }; + + int x1 = W, y1 = H, x2 = 0, y2 = 0; + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + for (int c = 0; c < 3; ++c) { + if (chan[c][y][x] >= clipscale[c]) { + anyclipped = true; + x1 = std::min(x, x1); + x2 = std::max(x, x2); + y1 = std::min(y, y1); + y2 = std::max(y, y2); + } + } + } + } + + if (!anyclipped) { + if (plistener) { + plistener->setProgress(1.0); + } + return; + } + + x1 = std::max(x1-1, 0); + x2 = std::min(x2+1, W-1); + y1 = std::max(y1-1, 0); + y2 = std::min(y2+1, H-1); + + const int cW = x2 - x1 + 1; + const int cH = y2 - y1 + 1; + +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int y = 0; y < cH; ++y) { + const int yy = y + y1; + for (int x = 0; x < cW; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + chan[c][yy][xx] *= scalecoeffs[c]; + } + } + } + + if (plistener) { + plistener->setProgress(0.1); + } + + multi_array2D tmp(cW, cH); + + const int pwidth = cW + 2 * HL_BORDER; + const int pheight = cH + 2 * HL_BORDER; + const int p_size = pwidth * pheight; + AlignedBuffer mask_vec(4 * p_size); + int *mask_buffer = mask_vec.data; + + const auto mask_val = + [&](int c, int y, int x) -> int & + { + return mask_buffer[c * p_size + (HL_BORDER + y) * pwidth + x + HL_BORDER]; + }; + + const auto set_refavg = + [&](int y, int x) -> bool + { + const int yy = y + y1; + const int xx = x + x1; + bool found = false; + for (int c = 0; c < 3 && !found; ++c) { + if (chan[c][yy][xx] >= clips[c]) { + found = true; + } + } + if (!found) { + return false; + } + + float mean[3] = { 0.0f, 0.0f, 0.0f }; + for (int dy = -1; dy < 2; dy++) { + for (int dx = -1; dx < 2; dx++) { + for (int c = 0; c < 3; ++c) { + mean[c] += std::max(0.0f, chan[c][yy+dy][xx+dx]); + } + } + } + for (int c = 0; c < 3; ++c) { + mean[c] = pow_F(mean[c] / 9.0f, 1.0f / HL_POWERF); + } + + const float croot_refavg[3] = { + 0.5f * (mean[1] + mean[2]), + 0.5f * (mean[0] + mean[2]), + 0.5f * (mean[0] + mean[1]) + }; + + for (int c = 0; c < 3; ++c) { + if (chan[c][yy][xx] >= clips[c]) { + tmp[c][y][x] = pow_F(croot_refavg[c], HL_POWERF); + mask_val(c, y, x) = 1; + } + } + return true; + }; + +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int y = 0; y < cH; ++y) { + const int yy = y + y1; + for (int x = 0; x < cW; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + tmp[c][y][x] = std::max(0.f, chan[c][yy][xx]); + } + + if ((x > 0) && (x < cW - 1) && (y > 0) && (y < cH - 1)) { + set_refavg(y, x); + } + } + } + + if (plistener) { + plistener->setProgress(0.3); + } + + for (size_t i = 0; i < 3; i++) { + int *mask = mask_buffer + i * p_size; + int *tmp = mask_buffer + 3 * p_size; + //border_fill_zero(mask, pwidth, pheight); + dilating(mask, tmp, pwidth, pheight); + memcpy(mask, tmp, p_size * sizeof(int)); + } + + float cr_sum[3] = { 0.f, 0.f, 0.f }; + int cr_cnt[3] = { 0, 0, 0 }; + +#ifdef _OPENMP +# pragma omp parallel for reduction(+ : cr_sum, cr_cnt) +#endif + for (int y = 1; y < cH-1; ++y) { + const int yy = y + y1; + for (int x = 1; x < cW-1; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + const float inval = std::max(0.0f, chan[c][yy][xx]); + if (mask_val(c, y, x) && (inval > clipdark[c]) && (inval < clips[c])) { + cr_sum[c] += inval - tmp[c][y][x]; + ++cr_cnt[c]; + } + } + } + } + + if (plistener) { + plistener->setProgress(0.6); + } + + float chrominance[3] = { + cr_sum[0] / std::max(1.f, float(cr_cnt[0])), + cr_sum[1] / std::max(1.f, float(cr_cnt[1])), + cr_sum[2] / std::max(1.f, float(cr_cnt[2])) + }; + +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int y = 0; y < cH; ++y) { + const int yy = y + y1; + for (int x = 0; x < cW; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + const float inval = std::max(0.0f, chan[c][yy][xx]); + if (inval >= clips[c]) { + chan[c][yy][xx] = std::max(inval, tmp[c][y][x] + chrominance[c]); + } + } + } + } + + if (plistener) { + plistener->setProgress(0.9); + } + +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int y = 0; y < cH; ++y) { + const int yy = y + y1; + for (int x = 0; x < cW; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + chan[c][yy][xx] /= scalecoeffs[c]; + } + } + } + + if (plistener) { + plistener->setProgress(1.0); + } +} + + + + } diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 2c75a0d59..cdb7dd6eb 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -111,7 +111,7 @@ public: { rm = gm = bm = 1.0; } - virtual 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) + virtual 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, const procparams::ToneCurveParams &hrp) { rm = gm = bm = 1.0; } @@ -1882,7 +1882,13 @@ public: * @param bps can be 8 or 16 depending on the bits per pixels the output file will have * @param isFloat is true for saving float images. Will be ignored by file format not supporting float data @return the error code, 0 if none */ - virtual int saveAsTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const = 0; + virtual int saveAsTIFF ( + const Glib::ustring &fname, + int bps = -1, + bool isFloat = false, + bool uncompressed = false, + bool big = false + ) const = 0; /** @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; diff --git a/rtengine/image16.h b/rtengine/image16.h index 25b777832..273ae63a1 100644 --- a/rtengine/image16.h +++ b/rtengine/image16.h @@ -81,7 +81,7 @@ public: return saveJPEG(fname, quality, subSamp); } - int saveAsTIFF(const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const override + int saveAsTIFF(const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false, bool big = false) const override { return saveTIFF(fname, bps, isFloat, uncompressed); } diff --git a/rtengine/image8.h b/rtengine/image8.h index 76a580bb6..416dc9143 100644 --- a/rtengine/image8.h +++ b/rtengine/image8.h @@ -79,9 +79,15 @@ public: return saveJPEG (fname, quality, subSamp); } - int saveAsTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const override + int saveAsTIFF ( + const Glib::ustring &fname, + int bps = -1, + bool isFloat = false, + bool uncompressed = false, + bool big = false + ) const override { - return saveTIFF (fname, bps, isFloat, uncompressed); + return saveTIFF (fname, bps, isFloat, uncompressed, big); } void setSaveProgressListener (ProgressListener* pl) override diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 3c10e7dc0..fb2fcaf3a 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -19,6 +19,7 @@ #include #include +#include #include @@ -57,7 +58,8 @@ template T getFromFrame( const std::vector>& frames, std::size_t frame, - const std::function& function + const std::function& function, + T defval = {} ) { if (frame < frames.size()) { @@ -66,7 +68,7 @@ T getFromFrame( if (!frames.empty()) { return function(*frames[0]); } - return {}; + return defval; } const std::string& validateUft8(const std::string& str, const std::string& on_error = "???") @@ -85,11 +87,21 @@ FramesMetaData* FramesMetaData::fromFile(const Glib::ustring& fname, std::unique return new FramesData(fname, std::move(rml), firstFrameOnly); } -FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir) : +static struct tm timeFromTS(const time_t ts) +{ +#if !defined(WIN32) + struct tm tm; + return *gmtime_r(&ts, &tm); +#else + return *gmtime(&ts); +#endif +} + +FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir, time_t ts) : frameRootDir(frameRootDir_), iptc(nullptr), - time{}, - timeStamp{}, + time(timeFromTS(ts)), + timeStamp(ts), iso_speed(0), aperture(0.), focal_len(0.), @@ -1068,7 +1080,8 @@ tm FramesData::getDateTime(unsigned int frame) const [](const FrameData& frame_data) { return frame_data.getDateTime(); - } + }, + modTime ); } @@ -1080,7 +1093,8 @@ time_t FramesData::getDateTimeAsTS(unsigned int frame) const [](const FrameData& frame_data) { return frame_data.getDateTimeAsTS(); - } + }, + modTimeStamp ); } @@ -1366,6 +1380,11 @@ failure: FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) : iptc(nullptr), dcrawFrameCount(0) { + GStatBuf statbuf = {}; + g_stat(fname.c_str(), &statbuf); + modTimeStamp = statbuf.st_mtime; + modTime = timeFromTS(modTimeStamp); + if (rml && (rml->exifBase >= 0 || rml->ciffBase >= 0)) { FILE* f = g_fopen(fname.c_str(), "rb"); @@ -1384,7 +1403,7 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0), modTimeStamp))); } for (auto currRoot : roots) { @@ -1410,7 +1429,7 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0), modTimeStamp))); } rewind(exifManager.f); // Not sure this is necessary @@ -1430,7 +1449,7 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0), modTimeStamp))); } for (auto currRoot : roots) { diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index 4bf9bdf5b..752fafab3 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -72,7 +72,7 @@ protected: public: - FrameData (rtexif::TagDirectory* frameRootDir, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir); + FrameData (rtexif::TagDirectory* frameRootDir, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir, time_t ts = 0); virtual ~FrameData (); bool getPixelShift () const; @@ -109,6 +109,8 @@ private: std::vector roots; IptcData* iptc; unsigned int dcrawFrameCount; + struct tm modTime; + time_t modTimeStamp; public: explicit FramesData (const Glib::ustring& fname, std::unique_ptr rml = nullptr, bool firstFrameOnly = false); diff --git a/rtengine/imagefloat.h b/rtengine/imagefloat.h index fc3ba318d..d69df9325 100644 --- a/rtengine/imagefloat.h +++ b/rtengine/imagefloat.h @@ -82,9 +82,15 @@ public: { return saveJPEG (fname, quality, subSamp); } - int saveAsTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const override + int saveAsTIFF ( + const Glib::ustring &fname, + int bps = -1, + bool isFloat = false, + bool uncompressed = false, + bool big = false + ) const override { - return saveTIFF (fname, bps, isFloat, uncompressed); + return saveTIFF (fname, bps, isFloat, uncompressed, big); } void setSaveProgressListener (ProgressListener* pl) override { diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index ce44d1ff4..ad230bb7d 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -17,21 +17,19 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include -#include -#include -#include #include #include -#include -#include #include -#include "rt_math.h" -#include "procparams.h" -#include "utils.h" -#include "../rtgui/options.h" -#include "../rtgui/version.h" -#include "../rtexif/rtexif.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include #ifdef WIN32 #include @@ -39,12 +37,20 @@ #include #endif +#include "color.h" +#include "iccjpeg.h" #include "imageio.h" #include "iptcpairs.h" -#include "iccjpeg.h" -#include "color.h" - #include "jpeg.h" +#include "procparams.h" +#include "rt_math.h" +#include "utils.h" + +#include "../rtgui/options.h" +#include "../rtgui/version.h" + +#include "../rtexif/rtexif.h" + using namespace std; using namespace rtengine; @@ -1328,7 +1334,13 @@ int ImageIO::saveJPEG (const Glib::ustring &fname, int quality, int subSamp) con return IMIO_SUCCESS; } -int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool uncompressed) const +int ImageIO::saveTIFF ( + const Glib::ustring &fname, + int bps, + bool isFloat, + bool uncompressed, + bool big +) const { if (getWidth() < 1 || getHeight() < 1) { return IMIO_HEADERERROR; @@ -1342,23 +1354,35 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u bps = getBPS (); } - int lineWidth = width * 3 * bps / 8; - unsigned char* linebuffer = new unsigned char[lineWidth]; + int lineWidth = width * 3 * (bps / 8); + std::vector linebuffer(lineWidth); + + std::string mode = "w"; // little hack to get libTiff to use proper byte order (see TIFFClienOpen()): - const char *mode = !exifRoot ? "w" : (exifRoot->getOrder() == rtexif::INTEL ? "wl" : "wb"); + if (exifRoot) { + if (exifRoot->getOrder() == rtexif::INTEL) { + mode += 'l'; + } else { + mode += 'b'; + } + } + + if (big) { + mode += '8'; + } + #ifdef WIN32 FILE *file = g_fopen_withBinaryAndLock (fname); int fileno = _fileno(file); int osfileno = _get_osfhandle(fileno); - TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode); + TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode.c_str()); #else - TIFF* out = TIFFOpen(fname.c_str(), mode); + TIFF* out = TIFFOpen(fname.c_str(), mode.c_str()); int fileno = TIFFFileno (out); #endif if (!out) { - delete [] linebuffer; return IMIO_CANNOTWRITEFILE; } @@ -1369,7 +1393,7 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u bool applyExifPatch = false; - if (exifRoot) { + if (exifRoot && !big) { rtexif::TagDirectory* cl = (const_cast (exifRoot))->clone (nullptr); // ------------------ remove some unknown top level tags which produce warnings when opening a tiff (might be useless) ----------------- @@ -1452,24 +1476,19 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u } #if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::MOTOROLA; + bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::MOTOROLA; #else - bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::INTEL; + bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::INTEL; #endif + if (iptcdata) { rtexif::Tag iptcTag(nullptr, rtexif::lookupAttrib (rtexif::ifdAttribs, "IPTCData")); iptcTag.initLongArray((char*)iptcdata, iptclen); if (needsReverse) { unsigned char *ptr = iptcTag.getValue(); - for (int a = 0; a < iptcTag.getCount(); ++a) { - unsigned char cc; - cc = ptr[3]; - ptr[3] = ptr[0]; - ptr[0] = cc; - cc = ptr[2]; - ptr[2] = ptr[1]; - ptr[1] = cc; - ptr += 4; + for (int a = 0; a < iptcTag.getCount(); ++a, ptr += 4) { + std::swap(ptr[0], ptr[3]); + std::swap(ptr[1], ptr[2]); } } TIFFSetField (out, TIFFTAG_RICHTIFFIPTC, iptcTag.getCount(), (long*)iptcTag.getValue()); @@ -1509,32 +1528,25 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u } for (int row = 0; row < height; row++) { - getScanline (row, linebuffer, bps, isFloat); + getScanline (row, linebuffer.data(), bps, isFloat); if (bps == 16) { if(needsReverse && !uncompressed && isFloat) { for(int i = 0; i < lineWidth; i += 2) { - char temp = linebuffer[i]; - linebuffer[i] = linebuffer[i + 1]; - linebuffer[i + 1] = temp; + std::swap(linebuffer[i], linebuffer[i + 1]); } } } else if (bps == 32) { if(needsReverse && !uncompressed) { for(int i = 0; i < lineWidth; i += 4) { - char temp = linebuffer[i]; - linebuffer[i] = linebuffer[i + 3]; - linebuffer[i + 3] = temp; - temp = linebuffer[i + 1]; - linebuffer[i + 1] = linebuffer[i + 2]; - linebuffer[i + 2] = temp; + std::swap(linebuffer[i], linebuffer[i + 3]); + std::swap(linebuffer[i + 1], linebuffer[i + 2]); } } } - if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) { + if (TIFFWriteScanline (out, linebuffer.data(), row, 0) < 0) { TIFFClose (out); - delete [] linebuffer; return IMIO_CANNOTWRITEFILE; } @@ -1584,8 +1596,6 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u fclose (file); #endif - delete [] linebuffer; - if (pl) { pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 566fef13b..e900feccd 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -113,7 +113,13 @@ public: int savePNG (const Glib::ustring &fname, int bps = -1) const; int saveJPEG (const Glib::ustring &fname, int quality = 100, int subSamp = 3) const; - int saveTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const; + int saveTIFF ( + const Glib::ustring &fname, + int bps = -1, + bool isFloat = false, + bool uncompressed = false, + bool big = false + ) const; cmsHPROFILE getEmbeddedProfile () const; void getEmbeddedProfileData (int& length, unsigned char*& pdata) const; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 6cb279efc..d6d22c269 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -109,7 +109,7 @@ public: 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; + virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hlp, const procparams::RAWParams &raw, int opposed) = 0; virtual eSensorType getSensorType () const = 0; virtual bool isMono () const = 0; // true is ready to provide the AutoWB, i.e. when the image has been demosaiced for RawImageSource @@ -117,10 +117,10 @@ public: virtual void convertColorSpace (Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) = 0; // DIRTY HACK: this method is derived in rawimagesource and strimagesource, but (...,RAWParams raw) will be used ONLY for raw images virtual void getAutoWBMultipliers (double &rm, double &gm, double &bm) = 0; - virtual 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) = 0; + virtual 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, const procparams::ToneCurveParams &hrp) = 0; virtual ColorTemp getWB () const = 0; virtual ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) = 0; - virtual void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) = 0; + virtual void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) = 0; virtual void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) = 0; virtual double getDefGain () const @@ -137,6 +137,7 @@ public: virtual ImageMatrices* getImageMatrices () = 0; virtual bool isRAW () const = 0; + virtual bool isGainMapSupported () const = 0; virtual DCPProfile* getDCP (const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) { return nullptr; @@ -194,6 +195,9 @@ public: } virtual void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) = 0; virtual void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) = 0; + virtual void wbMul2Camera(double &rm, double &gm, double &bm) = 0; + virtual void wbCamera2Mul(double &rm, double &gm, double &bm) = 0; + }; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 9eb7043d1..9437f1a75 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1,6 +1,6 @@ /* * This file is part of RawTherapee. - * + * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify @@ -163,6 +163,7 @@ ImProcCoordinator::ImProcCoordinator() : imageTypeListener(nullptr), filmNegListener(nullptr), actListener(nullptr), + primListener(nullptr), adnListener(nullptr), awavListener(nullptr), dehaListener(nullptr), @@ -407,13 +408,15 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // If high detail (=100%) is newly selected, do a demosaic update, since the last was just with FAST if (imageTypeListener) { - imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono()); + imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono(), imgsrc->isGainMapSupported()); } - + bool iscolor = (params->toneCurve.method == "Color");// || params->toneCurve.method == "Coloropp"); if ((todo & M_RAW) || (!highDetailRawComputed && highDetailNeeded) - || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) - || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { + // || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) + // || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { + || (params->toneCurve.hrenabled && !iscolor && imgsrc->isRGBSourceModified()) + || (!params->toneCurve.hrenabled && iscolor && imgsrc->isRGBSourceModified())) { if (settings->verbose) { if (imgsrc->getSensorType() == ST_BAYER) { @@ -466,8 +469,10 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if ((todo & M_RAW) || (!highDetailRawComputed && highDetailNeeded) - || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) - || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { + // || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) + // || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { + || (params->toneCurve.hrenabled && !iscolor && imgsrc->isRGBSourceModified()) + || (!params->toneCurve.hrenabled && iscolor && imgsrc->isRGBSourceModified())) { if (highDetailNeeded) { highDetailRawComputed = true; } else { @@ -510,8 +515,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } if (todo & (M_INIT | M_LINDENOISE | M_HDR)) { MyMutex::MyLock initLock(minit); // Also used in crop window - - imgsrc->HLRecovery_Global(params->toneCurve); // this handles Color HLRecovery + // imgsrc->HLRecovery_Global(params->toneCurve); // this handles Color HLRecovery if (settings->verbose) { @@ -538,7 +542,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) printf("tempref=%f greref=%f\n", tempref, greenref); } - imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw); + imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw, params->toneCurve); if (params->wb.method == "autitcgreen") { params->wb.temperature = tempitc; @@ -617,8 +621,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) PreviewProps pp(0, 0, fw, fh, scale); // Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications ipf.setScale(scale); - - imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw); + int inpaintopposed = 1;//force getimage to use inpaint-opposed if enable, only once + imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw, inpaintopposed); if ((todo & M_SPOT) && params->spot.enabled && !params->spot.entries.empty()) { spotsDone = true; @@ -731,6 +735,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // Remove transformation if unneeded bool needstransform = ipf.needsTransform(fw, fh, imgsrc->getRotateDegree(), imgsrc->getMetaData()); + if ((needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled && !params->colorappearance.enabled))) { // Forking the image assert(oprevi); @@ -745,6 +750,14 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } + for (int sp = 0; sp < (int)params->locallab.spots.size(); sp++) { + if(params->locallab.spots.at(sp).expsharp && params->dirpyrequalizer.cbdlMethod == "bef") { + if(params->locallab.spots.at(sp).shardamping < 1) { + params->locallab.spots.at(sp).shardamping = 1; + } + } + } + if ((todo & (M_TRANSFORM | M_RGBCURVE)) && params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled && !params->colorappearance.enabled) { const int W = oprevi->getWidth(); const int H = oprevi->getHeight(); @@ -1904,7 +1917,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) adap = pow(2.0, E_V - 3.0); // cd / m2 // end calculation adaptation scene luminosity } - + if(params->colorappearance.catmethod == "symg") {//force abolute luminance scenescene to 400 in symmetric + adap = 400.; + } float d, dj, yb; bool execsharp = false; @@ -1926,24 +1941,60 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) 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); - - if ((params->colorappearance.autodegree || params->colorappearance.autodegreeout) && acListener && params->colorappearance.enabled && !params->colorappearance.presetcat02) { - acListener->autoCamChanged(100.* (double)d, 100.* (double)dj); + //call listener + if ((params->colorappearance.autodegree || params->colorappearance.autodegreeout) && acListener && params->colorappearance.enabled) { + if(params->colorappearance.catmethod == "symg") {//force chromatic adaptation to 90 in symmetric + d = 0.9; + dj = 0.9; + } + acListener->autoCamChanged(100.* (double)d, 100.* (double)dj); } - if (params->colorappearance.autoadapscen && acListener && params->colorappearance.enabled && !params->colorappearance.presetcat02) { - acListener->adapCamChanged(adap); //real value of adapt scene + if (params->colorappearance.autoadapscen && acListener && params->colorappearance.enabled) { + acListener->adapCamChanged(adap); //real value of adapt scene, force to 400 in symmetric } - if (params->colorappearance.autoybscen && acListener && params->colorappearance.enabled && !params->colorappearance.presetcat02) { + if (params->colorappearance.autoybscen && acListener && params->colorappearance.enabled) { + if(params->colorappearance.catmethod == "symg") {//force yb scene to 18 in symmetric + yb = 18; + } + acListener->ybCamChanged((int) yb); //real value Yb scene } - - // if (params->colorappearance.enabled && params->colorappearance.presetcat02 && params->colorappearance.autotempout) { - // if (params->colorappearance.enabled && params->colorappearance.presetcat02) { - // acListener->wbCamChanged(params->wb.temperature, params->wb.green); //real temp and tint - // acListener->wbCamChanged(params->wb.temperature, 1.f); //real temp and tint = 1. - // } + double tempsym = 5003.; + int wmodel = 0;//wmodel allows - arbitrary - choice of illuminant and temp with choice + if (params->colorappearance.wbmodel == "RawT") { + wmodel = 0; + } else if (params->colorappearance.wbmodel == "RawTCAT02") { + wmodel = 1; + } else if (params->colorappearance.wbmodel == "free") { + wmodel = 2;//force white balance in symmetric + } + + if(params->colorappearance.catmethod == "symg" && wmodel == 2) { + tempsym = params->wb.temperature;//force white balance in symmetric + } else { + if (params->colorappearance.illum == "iA") {//otherwise force illuminant source + tempsym = 2856.; + } else if (params->colorappearance.illum == "i41") { + tempsym = 4100.; + } else if (params->colorappearance.illum == "i50") { + tempsym = 5003.; + } else if (params->colorappearance.illum == "i55") { + tempsym = 5503.; + } else if (params->colorappearance.illum == "i60") { + tempsym = 6000. ; + } else if (params->colorappearance.illum == "i65") { + tempsym = 6504.; + } else if (params->colorappearance.illum == "i75") { + tempsym = 7504.; + } else if (params->colorappearance.illum == "ifree") { + tempsym = params->wb.temperature;//force white balance in symmetric + } + } + if (params->colorappearance.enabled && params->colorappearance.autotempout) { + acListener->wbCamChanged(tempsym, 1.f); //real temp and tint = 1. + } } else { // CIECAM is disabled, we free up its image buffer to save some space @@ -2415,7 +2466,7 @@ bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, dou double greenitc = 1.; float studgood = 1000.f; double tempref, greenref; - imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw); + imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw, params->toneCurve); if (rm != -1) { autoWB.update(rm, gm, bm, equal, tempBias); @@ -2602,7 +2653,7 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a currWB = ColorTemp(); // = no white balance } - imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw); + imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw, 0); ImProcFunctions ipf(&ppar, true); if (ipf.needsTransform(fW, fH, imgsrc->getRotateDegree(), imgsrc->getMetaData())) { diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 15ebcc2e6..0e08a28eb 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -54,7 +54,8 @@ #pragma GCC diagnostic warning "-Wextra" #pragma GCC diagnostic warning "-Wdouble-promotion" -namespace { +namespace +{ using namespace rtengine; @@ -218,32 +219,37 @@ void proPhotoBlue(float *rtemp, float *gtemp, float *btemp, int istart, int tH, } } -void customToneCurve(const ToneCurve &customToneCurve, ToneCurveMode curveMode, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize, PerceptualToneCurveState ptcApplyState) { +void customToneCurve(const ToneCurve &customToneCurve, ToneCurveMode curveMode, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize, PerceptualToneCurveState ptcApplyState) +{ if (curveMode == ToneCurveMode::STD) { // Standard - const StandardToneCurve& userToneCurve = static_cast (customToneCurve); + const StandardToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize]); } } else if (curveMode == ToneCurveMode::FILMLIKE) { // Adobe like - const AdobeToneCurve& userToneCurve = static_cast (customToneCurve); + const AdobeToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize]); } } else if (curveMode == ToneCurveMode::SATANDVALBLENDING) { // apply the curve on the saturation and value channels - const SatAndValueBlendingToneCurve& userToneCurve = static_cast (customToneCurve); + const SatAndValueBlendingToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { userToneCurve.Apply(rtemp[ti * tileSize + tj], gtemp[ti * tileSize + tj], btemp[ti * tileSize + tj]); } } } else if (curveMode == ToneCurveMode::WEIGHTEDSTD) { // apply the curve to the rgb channels, weighted - const WeightedStdToneCurve& userToneCurve = static_cast (customToneCurve); + const WeightedStdToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize]); } } else if (curveMode == ToneCurveMode::LUMINANCE) { // apply the curve to the luminance channel - const LuminanceToneCurve& userToneCurve = static_cast (customToneCurve); + const LuminanceToneCurve& userToneCurve = static_cast(customToneCurve); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { @@ -251,7 +257,8 @@ void customToneCurve(const ToneCurve &customToneCurve, ToneCurveMode curveMode, } } } else if (curveMode == ToneCurveMode::PERCEPTUAL) { // apply curve while keeping color appearance constant - const PerceptualToneCurve& userToneCurve = static_cast (customToneCurve); + const PerceptualToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize], ptcApplyState); } @@ -277,7 +284,7 @@ namespace rtengine using namespace procparams; -ImProcFunctions::~ImProcFunctions () +ImProcFunctions::~ImProcFunctions() { if (monitorTransform) { cmsDeleteTransform(monitorTransform); @@ -307,7 +314,7 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB monitor = ICCStore::getInstance()->getProfile(monitorProfile); #else - monitor = ICCStore::getInstance()->getProfile (settings->srgb); + monitor = ICCStore::getInstance()->getProfile(settings->srgb); #endif } @@ -325,7 +332,7 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R if (softProof) { cmsHPROFILE oprof = nullptr; RenderingIntent outIntent; - + flags = cmsFLAGS_SOFTPROOFING | cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; if (!settings->printerProfile.empty()) { @@ -334,9 +341,11 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R if (settings->printerBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; } + outIntent = RenderingIntent(settings->printerIntent); } else { oprof = ICCStore::getInstance()->getProfile(params->icm.outputProfile); + if (params->icm.outputBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; } @@ -352,20 +361,23 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R // } const auto make_gamma_table = - [](cmsHPROFILE prof, cmsTagSignature tag) -> void + [](cmsHPROFILE prof, cmsTagSignature tag) -> void { + cmsToneCurve *tc = static_cast(cmsReadTag(prof, tag)); + + if (tc) { - cmsToneCurve *tc = static_cast(cmsReadTag(prof, tag)); - if (tc) { - const cmsUInt16Number *table = cmsGetToneCurveEstimatedTable(tc); - cmsToneCurve *tc16 = cmsBuildTabulatedToneCurve16(nullptr, cmsGetToneCurveEstimatedTableEntries(tc), table); - if (tc16) { - cmsWriteTag(prof, tag, tc16); - cmsFreeToneCurve(tc16); - } + const cmsUInt16Number *table = cmsGetToneCurveEstimatedTable(tc); + cmsToneCurve *tc16 = cmsBuildTabulatedToneCurve16(nullptr, cmsGetToneCurveEstimatedTableEntries(tc), table); + + if (tc16) { + cmsWriteTag(prof, tag, tc16); + cmsFreeToneCurve(tc16); } - }; + } + }; cmsHPROFILE softproof = ProfileContent(oprof).toProfile(); + if (softproof) { make_gamma_table(softproof, cmsSigRedTRCTag); make_gamma_table(softproof, cmsSigGreenTRCTag); @@ -439,7 +451,7 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R void ImProcFunctions::firstAnalysis(const Imagefloat* const original, const ProcParams ¶ms, LUTu & histogram) { - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.workingProfile); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params.icm.workingProfile); lumimul[0] = wprof[1][0]; lumimul[1] = wprof[1][1]; @@ -956,18 +968,20 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb float cz, wh, pfl; int c16 = 1; + if (params->colorappearance.modelmethod == "02") { c16 = 1; - }else if (params->colorappearance.modelmethod == "16") { + } else if (params->colorappearance.modelmethod == "16") { c16 = 16; - } //I don't use PQ here...hence no 21 + } //I don't use PQ here...hence no 21 + float plum = 100.f; - Ciecam02::initcam1float (yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c, c16, plum); + Ciecam02::initcam1float(yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c, c16, plum); //printf ("wh=%f \n", wh); 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, c16, plum); + Ciecam02::initcam2float(yb2, pilotout, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj, c16, plum); #ifdef __SSE2__ const float reccmcz = 1.f / (c2 * czj); #endif @@ -1011,7 +1025,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb //matrix for current working space - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.workingProfile); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(params->icm.workingProfile); const float wip[3][3] = { { (float)wiprof[0][0], (float)wiprof[0][1], (float)wiprof[0][2]}, { (float)wiprof[1][0], (float)wiprof[1][1], (float)wiprof[1][2]}, @@ -1084,7 +1098,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb Q, M, s, aw, fl, wh, x, y, z, xw1, yw1, zw1, - c, nc, pow1, nbb, ncb, pfl, cz, d, c16, plum); + c, nc, pow1, nbb, ncb, pfl, cz, d, c16, plum); Jbuffer[k] = J; Cbuffer[k] = C; hbuffer[k] = h; @@ -1122,7 +1136,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb Q, M, s, aw, fl, wh, x, y, z, xw1, yw1, zw1, - c, nc, pow1, nbb, ncb, pfl, cz, d, c16, plum); + c, nc, pow1, nbb, ncb, pfl, cz, d, c16, plum); #endif float Jpro, Cpro, hpro, Qpro, Mpro, spro; Jpro = J; @@ -1132,6 +1146,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb Mpro = M; spro = s; bool jp = false; + if ((hasColCurve1) && (curveMode == ColorAppearanceParams::TcMode::BRIGHT)) { jp = true; float Qq = Qpro * coefQ; @@ -1141,6 +1156,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb Qq = Qq / coefQ; Qpro = 0.2f * (Qq - Qold) + Qold; } + if ((hasColCurve2) && (curveMode2 == ColorAppearanceParams::TcMode::BRIGHT)) { jp = true; float Qq2 = Qpro * coefQ; @@ -1149,10 +1165,12 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb userColCurveB2.Apply(Qq2); Qq2 = Qq2 / coefQ; Qpro = 0.2f * (Qq2 - Qold2) + Qold2; - } - if(jp) { + } + + if (jp) { Jpro = SQR((10.f * Qpro) / wh); } + // we cannot have all algorithms with all chroma curves if (alg == 0) { Jpro = CAMBrightCurveJ[Jpro * 327.68f]; //lightness CIECAM02 + contrast @@ -1240,73 +1258,73 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb } if (hasColCurve1 && (curveMode == ColorAppearanceParams::TcMode::LIGHT)) { - float Jj = (float) Jpro * 327.68f; - float Jold = Jj; - float Jold100 = (float) Jpro; - float redu = 25.f; - float reduc = 1.f; - const Lightcurve& userColCurveJ1 = static_cast(customColCurve1); - userColCurveJ1.Apply(Jj); + float Jj = (float) Jpro * 327.68f; + float Jold = Jj; + float Jold100 = (float) Jpro; + float redu = 25.f; + float reduc = 1.f; + 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); - Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights - } + 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); + Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } - } else if (Jj > 10.f) { - Jj = 0.8f * (Jj - Jold) + Jold; - } else if (Jj >= 0.f) { - Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts } + } else if (Jj > 10.f) { + Jj = 0.8f * (Jj - Jold) + Jold; + } else if (Jj >= 0.f) { + 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; - } + if (Jpro < 1.f) { + Jpro = 1.f; + } } - if (hasColCurve2 && (curveMode2 == ColorAppearanceParams::TcMode::LIGHT)) { - float Jj = (float) Jpro * 327.68f; - float Jold = Jj; - float Jold100 = (float) Jpro; - float redu = 25.f; - float reduc = 1.f; - const Lightcurve& userColCurveJ2 = static_cast(customColCurve2); - userColCurveJ2.Apply(Jj); + if (hasColCurve2 && (curveMode2 == ColorAppearanceParams::TcMode::LIGHT)) { + float Jj = (float) Jpro * 327.68f; + float Jold = Jj; + float Jold100 = (float) Jpro; + float redu = 25.f; + float reduc = 1.f; + 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); - Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights - } - } - } else if (Jj > 10.f) { - if (!t1L) { - Jj = 0.8f * (Jj - Jold) + Jold; - } else { - Jj = 0.4f * (Jj - Jold) + Jold; - } - } else if (Jj >= 0.f) { - if (!t1L) { - Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts - } else { - Jj = 0.5f * (Jj - Jold) + Jold; + 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); + Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } } - - Jpro = (float)(Jj / 327.68f); - - if (Jpro < 1.f) { - Jpro = 1.f; + } else if (Jj > 10.f) { + if (!t1L) { + Jj = 0.8f * (Jj - Jold) + Jold; + } else { + Jj = 0.4f * (Jj - Jold) + Jold; } + } else if (Jj >= 0.f) { + if (!t1L) { + Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts + } else { + Jj = 0.5f * (Jj - Jold) + Jold; + } + } + + Jpro = (float)(Jj / 327.68f); + + if (Jpro < 1.f) { + Jpro = 1.f; + } } if (hasColCurve3) {//curve 3 with chroma saturation colorfullness @@ -1456,47 +1474,33 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb #else float xx, yy, zz; //process normal==> viewing + TMatrix wprofc = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + const double wpc[3][3] = {//improve precision with double + {wprofc[0][0], wprofc[0][1], wprofc[0][2]}, + {wprofc[1][0], wprofc[1][1], wprofc[1][2]}, + {wprofc[2][0], wprofc[2][1], wprofc[2][2]} + }; Ciecam02::jch2xyz_ciecam02float(xx, yy, zz, J, C, h, xw2, yw2, zw2, - c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj, c16, plum); + c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj, c16, plum); float x, y, z; 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); - - // 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; - float2 sincosval; - - 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); - } - - - //gamut control : Lab values are in gamut - 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; - - } else { - lab->L[i][j] = Ll; - lab->a[i][j] = aa; - lab->b[i][j] = bb; + Color::gamutmap(x, y, z, wpc); } + Color::XYZ2Lab(x, y, z, Ll, aa, bb); + lab->L[i][j] = Ll; + lab->a[i][j] = aa; + lab->b[i][j] = bb; + #endif } } @@ -1592,7 +1596,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb if (params->defringe.enabled) if (execsharp) { lab->deleteLab(); - defringecam (ncie);//defringe adapted to CIECAM + defringecam(ncie); //defringe adapted to CIECAM lab->reallocLab(); } @@ -1603,7 +1607,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb const bool hotbad = params->dirpyrequalizer.skinprotect != 0.0; lab->deleteLab(); - badpixcam (ncie, artifact / scale, 5, 2, chrom, hotbad); //enabled remove artifacts for cbDL + badpixcam(ncie, artifact / scale, 5, 2, chrom, hotbad); //enabled remove artifacts for cbDL lab->reallocLab(); } @@ -1611,7 +1615,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb if (params->colorappearance.badpixsl > 0 && execsharp) { int mode = params->colorappearance.badpixsl; lab->deleteLab(); - badpixcam (ncie, 3.0, 10, mode, 0, true);//for bad pixels CIECAM + badpixcam(ncie, 3.0, 10, mode, 0, true); //for bad pixels CIECAM lab->reallocLab(); } @@ -1620,17 +1624,17 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb buffers[0] = lab->L; buffers[1] = lab->a; buffers[2] = lab->b; - impulsedenoisecam (ncie, buffers); //impulse adapted to CIECAM + impulsedenoisecam(ncie, buffers); //impulse adapted to CIECAM } if (params->sharpenMicro.enabled)if (execsharp) { - MLmicrocontrastcam (ncie); + MLmicrocontrastcam(ncie); } if (params->sharpening.enabled) if (execsharp) { float **buffer = lab->L; // We can use the L-buffer from lab as buffer to save some memory - sharpeningcam (ncie, buffer, showSharpMask); // sharpening adapted to CIECAM + sharpeningcam(ncie, buffer, showSharpMask); // sharpening adapted to CIECAM } //if(params->dirpyrequalizer.enabled) if(execsharp) { @@ -1643,7 +1647,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb 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 + 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(); } @@ -1666,6 +1670,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb #ifdef _OPENMP #pragma omp for schedule(dynamic, 10) #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)); @@ -1685,7 +1690,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb if (epdEnabled && params->colorappearance.tonecie && algepd) { lab->deleteLab(); - EPDToneMapCIE (ncie, a_w, c_, width, height, minQ, maxQ, Iterates, scale ); + EPDToneMapCIE(ncie, a_w, c_, width, height, minQ, maxQ, Iterates, scale); lab->reallocLab(); } @@ -1769,7 +1774,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb 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, c16, plum); + c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj, c16, plum); float x = (float)xx * 655.35f; float y = (float)yy * 655.35f; float z = (float)zz * 655.35f; @@ -1894,7 +1899,7 @@ void ImProcFunctions::moyeqt(Imagefloat* working, float &moyS, float &eqty) for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { - const double s = Color::rgb2s(CLIP(working->r (i, j)), CLIP(working->g (i, j)), CLIP(working->b (i, j))); + const double s = Color::rgb2s(CLIP(working->r(i, j)), CLIP(working->g(i, j)), CLIP(working->b(i, j))); moy += s; sqrs += SQR(s); } @@ -1946,12 +1951,12 @@ filmlike_clip(float *r, float *g, float *b) } } -void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, - int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, - const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, - const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, - double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, - LUTu& histToneCurve, size_t chunkSize, bool measure) +void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, + int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, + const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, + const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, + LUTu& histToneCurve, size_t chunkSize, bool measure) { rgbProc(working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, sat, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, @@ -1959,12 +1964,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } // Process RGB image and convert to LAB space -void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, - int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, - const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, - const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, - double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, - DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) +void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, + int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, + const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, + const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, + DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) { std::unique_ptr stop; @@ -1995,8 +2000,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } } - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params->icm.workingProfile); - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.workingProfile); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(params->icm.workingProfile); float toxyz[3][3] = { { @@ -2150,13 +2155,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer PerceptualToneCurveState ptc1ApplyState, ptc2ApplyState; if (hasToneCurve1 && curveMode == ToneCurveMode::PERCEPTUAL) { - const PerceptualToneCurve& userToneCurve = static_cast (customToneCurve1); - userToneCurve.initApplyState (ptc1ApplyState, params->icm.workingProfile); + const PerceptualToneCurve& userToneCurve = static_cast(customToneCurve1); + userToneCurve.initApplyState(ptc1ApplyState, params->icm.workingProfile); } if (hasToneCurve2 && curveMode2 == ToneCurveMode::PERCEPTUAL) { - const PerceptualToneCurve& userToneCurve = static_cast (customToneCurve2); - userToneCurve.initApplyState (ptc2ApplyState, params->icm.workingProfile); + const PerceptualToneCurve& userToneCurve = static_cast(customToneCurve2); + userToneCurve.initApplyState(ptc2ApplyState, params->icm.workingProfile); } bool hasColorToning = params->colorToning.enabled && bool (ctOpacityCurve) && bool (ctColorCurve) && params->colorToning.method != "LabGrid"; @@ -2351,6 +2356,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } highlightToneCurve(hltonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS, exp_scale, comp, hlrange); + if (params->toneCurve.black != 0.0) { shadowToneCurve(shtonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS); } @@ -2402,7 +2408,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float tmpg[4] ALIGNED16; float tmpb[4] ALIGNED16; - for (; j < tW - 3; j+=4, tj+=4) { + for (; j < tW - 3; j += 4, tj += 4) { //brightness/contrast STVF(tmpr[0], tonecurve(LVF(rtemp[ti * TS + tj]))); STVF(tmpg[0], tonecurve(LVF(gtemp[ti * TS + tj]))); @@ -2683,6 +2689,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer else if (params->colorToning.method == "Splitco") { constexpr float reducac = 0.3f; constexpr int mode = 0; + for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { const float r = rtemp[ti * TS + tj]; @@ -3113,9 +3120,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer 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); - // } + // if (hasColorToningLabGrid) { + // colorToningLabGrid(lab, jstart, tW, istart, tH, false); + // } } else { // black & white // Auto channel mixer needs whole image, so we now copy to tmpImage and close the tiled processing for (int i = istart, ti = 0; i < tH; i++, ti++) { @@ -3494,9 +3501,9 @@ 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); - // } + // if (hasColorToningLabGrid) { + // colorToningLabGrid(lab, 0, tW, i, i + 1, false); + // } } @@ -3511,7 +3518,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (sCurveEnabled) { - delete sCurve; + delete sCurve; } if (vCurveEnabled) { @@ -3955,7 +3962,7 @@ void ImProcFunctions::toning2col(float r, float g, float b, float &ro, float &go * @param iplow iphigh [0..1] luminance * @param wp wip 3x3 matrix and inverse conversion rgb XYZ **/ -void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, const LUTf & clToningcurve, const LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3] ) +void ImProcFunctions::labtoning(float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, const LUTf & clToningcurve, const LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3]) { ro = CLIP(r); go = CLIP(g); @@ -4014,7 +4021,7 @@ void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go } -void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, const LUTf& curve) +void ImProcFunctions::luminanceCurve(LabImage* lold, LabImage* lnew, const LUTf& curve) { int W = lold->W; @@ -4034,7 +4041,7 @@ 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) +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; @@ -4069,7 +4076,8 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // !params->labCurve.enabled. It is ugly, but it's the smallest code // change that I could find //------------------------------------------------------------------------- - class TempParams { + class TempParams + { const ProcParams **p_; const ProcParams *old_; ProcParams tmp_; @@ -4091,11 +4099,13 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW bool pipette_for_colortoning_labregions = editPipette && params->colorToning.enabled && params->colorToning.method == "LabRegions"; + if (!params->labCurve.enabled && pipette_for_colortoning_labregions) { utili = autili = butili = ccutili = cclutili = clcutili = false; tempparams.reset(new TempParams(¶ms)); curve.makeIdentity(); } + //------------------------------------------------------------------------- @@ -4104,6 +4114,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // fill pipette buffer with zeros to avoid crashes editWhatever->fill(0.f); } + if (params->blackwhite.enabled && !params->colorToning.enabled) { for (int i = 0; i < lnew->H; ++i) { for (int j = 0; j < lnew->W; ++j) { @@ -4111,6 +4122,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW } } } + return; } @@ -4172,7 +4184,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // if(params->labCurve.avoidclip ){ // parameter to adapt curve C=f(C) to gamut - if (params->icm.workingProfile == "ProPhoto") { + 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; @@ -4203,7 +4215,22 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW const bool clut = clcutili; const double rstprotection = 100. - params->labCurve.rstprotection; // Red and Skin Tones Protection // avoid color shift is disabled when bwToning is activated and enabled if gamut is true in colorappearanace - const bool avoidColorShift = (params->labCurve.avoidcolorshift || (params->colorappearance.gamut && params->colorappearance.enabled)) && !bwToning ; + // const bool avoidColorShift = (params->labCurve.avoidcolorshift || (params->colorappearance.gamut && params->colorappearance.enabled)) && !bwToning ; + //const bool avoidColorS = params->labCurve.avoidcolorshift; + int gamutmuns = 0; + + if (params->labCurve.gamutmunselmethod == "NONE") { + gamutmuns = 0; + } else if (params->labCurve.gamutmunselmethod == "LAB") { + gamutmuns = 1; + } else if (params->labCurve.gamutmunselmethod == "XYZ") { + gamutmuns = 2; + } else if (params->labCurve.gamutmunselmethod == "XYZREL") { + gamutmuns = 3; + } else if (params->labCurve.gamutmunselmethod == "MUN") { + gamutmuns = 4; + } + const float protectRed = (float)settings->protectred; const double protectRedH = settings->protectredh; const float protect_red = rtengine::LIM(protectRed, 20.f, 180.f); //default=60 chroma: one can put more or less if necessary...in 'option' 40...160 @@ -4228,17 +4255,17 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW const float scaleConst = 100.0f / 100.1f; - const bool gamutLch = settings->gamutLch; + //const bool gamutLch = settings->gamutLch; const float amountchroma = (float) settings->amchroma; - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.workingProfile); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(params->icm.workingProfile); const double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, {wiprof[2][0], wiprof[2][1], wiprof[2][2]} }; - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params->icm.workingProfile); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); const double wp[3][3] = { {wprof[0][0], wprof[0][1], wprof[0][2]}, {wprof[1][0], wprof[1][1], wprof[1][2]}, @@ -4258,12 +4285,12 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW #endif for (int i = 0; i < H; i++) { - if (avoidColorShift) + // if (avoidColorShift) - // 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); - } + // 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); + // } #ifdef __SSE2__ @@ -4277,7 +4304,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW 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); + STVF(CCBuffer[k], vsqrtf(SQRV(av) + SQRV(bv)) / c327d68v); } for (; k < W; k++) { @@ -4431,8 +4458,8 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW float fx = (0.002f * aprov1) + fy; float fz = fy - (0.005f * bprov1); - float x_ = 65535.f * Color::f2xyz (fx) * Color::D50x; - float z_ = 65535.f * Color::f2xyz (fz) * Color::D50z; + float x_ = 65535.f * Color::f2xyz(fx) * Color::D50x; + 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); @@ -4704,24 +4731,57 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW btmp -= lold->b[i][j]; } - if (avoidColorShift) { - //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; - //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); - lnew->L[i][j] = Lprov1 * 327.68f; - 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); - //Yuv2Lab includes gamut restriction map - Color::Yuv2Lab(Y, u, v, lnew->L[i][j], lnew->a[i][j], lnew->b[i][j], wp); + lnew->L[i][j] = Lprov1 * 327.68f; + lnew->a[i][j] = 327.68f * Chprov1 * sincosval.y; + lnew->b[i][j] = 327.68f * Chprov1 * sincosval.x; + + //gamutmap Lch ==> preserve Hue,but a little slower than gamutbdy for high values...and little faster for low values + if (gamutmuns == 1) { + float R, G, B; + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); + lnew->L[i][j] = Lprov1 * 327.68f; + lnew->a[i][j] = 327.68f * Chprov1 * sincosval.y; + lnew->b[i][j] = 327.68f * Chprov1 * sincosval.x; + } + + if (gamutmuns == 2 || gamutmuns == 3) { + + float xg, yg, zg; + Color::Lab2XYZ(lnew->L[i][j], atmp, btmp, xg, yg, zg); + float x0 = xg; + float y0 = yg; + float z0 = zg; + + Color::gamutmap(xg, yg, zg, wp); + + if (gamutmuns == 3) {//0.5f arbitrary coeff + xg = xg + 0.5f * (x0 - xg); + yg = yg + 0.5f * (y0 - yg); + zg = zg + 0.5f * (z0 - zg); } + float Lag, aag2, bbg2; + Color::XYZ2Lab(xg, yg, zg, Lag, aag2, bbg2); + Lprov1 = Lag / 327.68f; + HH = xatan2f(bbg2, aag2); + Chprov1 = std::sqrt(SQR(aag2) + SQR(bbg2)) / 327.68f; + + if (Chprov1 == 0.0f) { + sincosval.y = 1.f; + sincosval.x = 0.0f; + } else { + sincosval.y = aag2 / (Chprov1 * 327.68f); + sincosval.x = bbg2 / (Chprov1 * 327.68f); + } + + lnew->L[i][j] = Lprov1 * 327.68f; + lnew->a[i][j] = 327.68f * Chprov1 * sincosval.y; + lnew->b[i][j] = 327.68f * Chprov1 * sincosval.x; + + } + + if (gamutmuns > 0) { if (utili || autili || butili || ccut || clut || cclutili || chutili || lhutili || hhutili || clcutili || chromaticity) { float correctionHue = 0.f; // Munsell's correction float correctlum = 0.f; @@ -4747,7 +4807,10 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW lnew->a[i][j] = 327.68f * Chprov * sincosval.y; // apply Munsell lnew->b[i][j] = 327.68f * Chprov * sincosval.x; } - } else { + } + + if (gamutmuns == 0) { + // if(Lprov1 > maxlp) maxlp=Lprov1; // if(Lprov1 < minlp) minlp=Lprov1; if (!bwToning) { @@ -4940,11 +5003,12 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, int Wid if (!params->epd.enabled) { return; } -/* - if (params->wavelet.enabled && params->wavelet.tmrs != 0) { - return; - } -*/ + + /* + if (params->wavelet.enabled && params->wavelet.tmrs != 0) { + return; + } + */ float stren = params->epd.strength; const float edgest = std::min(params->epd.edgeStopping, params->localContrast.enabled ? 3.0 : 4.0); float sca = params->epd.scale; @@ -4954,7 +5018,7 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, int Wid float *Qpr = ncie->Q_p[0]; if (settings->verbose) { - printf ("minQ=%f maxQ=%f Qpro=%f\n", static_cast(minQ), static_cast(maxQ), static_cast(Qpro)); + printf("minQ=%f maxQ=%f Qpro=%f\n", static_cast(minQ), static_cast(maxQ), static_cast(Qpro)); } if (maxQ > Qpro) { @@ -4993,6 +5057,7 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, int Wid #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,10) #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; @@ -5043,7 +5108,7 @@ void ImProcFunctions::EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, uns 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; @@ -5064,6 +5129,7 @@ void ImProcFunctions::EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, uns #ifdef _OPENMP #pragma omp parallel for reduction(max:maxL) reduction(min:minL) schedule(dynamic,16) #endif + for (std::size_t i = 0; i < N; i++) { minL = rtengine::min(minL, L[i]); maxL = rtengine::max(maxL, L[i]); @@ -5081,8 +5147,8 @@ void ImProcFunctions::EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, uns #ifdef _OPENMP #pragma omp parallel for #endif - for (std::size_t i = 0; i < N; i++) - { + + for (std::size_t i = 0; i < N; i++) { L[i] = (L[i] - minL) * mult; } @@ -5111,8 +5177,12 @@ void ImProcFunctions::EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, uns //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 sat = s + 0.3f * s * satur; + //printf("s=%f sat=%f \n", s, sat); - if(sat == 1.f) sat = 1.001f; + if (sat == 1.f) { + sat = 1.001f; + } + #ifdef _OPENMP #pragma omp parallel for // removed schedule(dynamic,10) #endif @@ -5159,6 +5229,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) #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]); @@ -5173,6 +5244,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) #ifdef _OPENMP #pragma omp parallel for #endif + for (size_t i = 0; i < N; ++i) { L[i] = (L[i] - minL) * (gamm / maxL); } @@ -5186,7 +5258,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) Iterates = edgest * 15.f; } - epd.CompressDynamicRange (L, sca / skip, edgest, Compression, DetailBoost, Iterates, rew); + 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)); @@ -5195,6 +5267,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) #ifdef _OPENMP #pragma omp parallel for #endif + for (size_t ii = 0; ii < N; ++ii) { a[ii] *= s; b[ii] *= s; @@ -5242,7 +5315,7 @@ void ImProcFunctions::getAutoExp(const LUTu &histogram, int histcompr, double cl int j = 0; - for (; j < min ((int)ave, imax); ++j) { + for (; j < min((int)ave, imax); ++j) { if (count < 8) { octile[count] += histogram[j]; @@ -5335,7 +5408,7 @@ void ImProcFunctions::getAutoExp(const LUTu &histogram, int histcompr, double cl } //compute clipped white point - unsigned int clippable = (int) (static_cast(sum) * clip / 100.0 ); + unsigned int clippable = (int)(static_cast(sum) * clip / 100.0); clipped = 0; int whiteclip = (imax) - 1; @@ -5414,7 +5487,7 @@ void ImProcFunctions::getAutoExp(const LUTu &histogram, int histcompr, double cl contr = (int) 50.0f * (1.1f - ospread); contr = max(0, min(100, contr)); //take gamma into account - double whiteclipg = (int) (CurveFactory::gamma2(whiteclip * static_cast(corr) / 65536.0) * 65536.0); + double whiteclipg = (int)(CurveFactory::gamma2(whiteclip * static_cast(corr) / 65536.0) * 65536.0); float gavg = 0.; @@ -5594,7 +5667,8 @@ void ImProcFunctions::rgb2lab(const Imagefloat &src, LabImage &dst, const Glib:: } 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 +{ + // Adapted from ImProcFunctions::lab2rgb const int src_width = src.getWidth(); const int src_height = src.getHeight(); @@ -5626,6 +5700,7 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo if (icm.outputProfile.empty() || icm.outputProfile == ColorManagementParams::NoICMString) { profile = "sRGB"; } + oprof = ICCStore::getInstance()->getProfile(profile); } @@ -5638,7 +5713,7 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo lcmsMutex->lock(); cmsHPROFILE LabIProf = cmsCreateLab4Profile(nullptr); - cmsHTRANSFORM hTransform = cmsCreateTransform (oprof, TYPE_RGB_8, LabIProf, TYPE_Lab_FLT, icm.outputIntent, flags); + cmsHTRANSFORM hTransform = cmsCreateTransform(oprof, TYPE_RGB_8, LabIProf, TYPE_Lab_FLT, icm.outputIntent, flags); cmsCloseProfile(LabIProf); lcmsMutex->unlock(); @@ -5662,7 +5737,7 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo float* ra = a + (i - y) * w; float* rb = b + (i - y) * w; - cmsDoTransform (hTransform, src.data + ix, outbuffer, w); + cmsDoTransform(hTransform, src.data + ix, outbuffer, w); for (int j = 0; j < w; j++) { rL[j] = outbuffer[iy++] * 327.68f; @@ -5691,6 +5766,7 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo 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. @@ -5782,7 +5858,7 @@ 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 diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 1be1d0371..36c571291 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -257,7 +257,7 @@ enum class BlurType { 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, float &fab); - void avoidcolshi(const struct local_params& lp, int sp, LabImage * original, LabImage *transformed, int cy, int cx, int sk); + void avoidcolshi(const struct local_params& lp, int sp, LabImage *transformed, LabImage *reserved, int cy, int cx, int sk); 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); diff --git a/rtengine/init.cc b/rtengine/init.cc index ff29c3476..4ec3f0ec5 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -58,10 +58,20 @@ int init (const Settings* s, const Glib::ustring& baseDir, const Glib::ustring& #pragma omp section #endif { + bool ok; + if (s->lensfunDbDirectory.empty() || Glib::path_is_absolute(s->lensfunDbDirectory)) { - LFDatabase::init(s->lensfunDbDirectory); + ok = LFDatabase::init(s->lensfunDbDirectory); } else { - LFDatabase::init(Glib::build_filename(baseDir, s->lensfunDbDirectory)); + ok = LFDatabase::init(Glib::build_filename(baseDir, s->lensfunDbDirectory)); + } + + if (!ok && !s->lensfunDbBundleDirectory.empty() && s->lensfunDbBundleDirectory != s->lensfunDbDirectory) { + if (Glib::path_is_absolute(s->lensfunDbBundleDirectory)) { + LFDatabase::init(s->lensfunDbBundleDirectory); + } else { + LFDatabase::init(Glib::build_filename(baseDir, s->lensfunDbBundleDirectory)); + } } } #ifdef _OPENMP diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index f48b2e52e..dd02b8f0f 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -416,6 +416,8 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, { const TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + double wprofprim[3][3];//store primaries to XYZ + bool gamutcontrol = params->icm.gamut; const float toxyz[3][3] = { { static_cast(wprof[0][0] / ((normalizeIn ? 65535.0 : 1.0))), //I have suppressed / Color::D50x @@ -440,57 +442,64 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, if (settings->verbose) { printf("profile not accepted\n"); } + return; } if (mul == -5 && gampos == 2.4 && slpos == 12.92310) {//must be change if we change settings RT sRGB //only in this case we can shortcut..all process..no gamut control..because we reduce...leads to very small differences, but big speedup #ifdef _OPENMP - #pragma omp parallel for schedule(dynamic, 16) if (multiThread) + #pragma omp parallel for schedule(dynamic, 16) if (multiThread) #endif - for (int i = 0; i < ch; ++i) - for (int j = 0; j < cw; ++j) { - float r = src->r(i, j); - float g = src->g(i, j); - float b = src->b(i, j); - r = (Color::igammatab_srgb[r]) / 65535.f; - g = (Color::igammatab_srgb[g]) / 65535.f; - b = (Color::igammatab_srgb[b]) / 65535.f; - dst->r(i, j) = r; - dst->g(i, j) = g; - dst->b(i, j) = b; - } - return; + for (int i = 0; i < ch; ++i) + for (int j = 0; j < cw; ++j) { + float r = src->r(i, j); + float g = src->g(i, j); + float b = src->b(i, j); + r = (Color::igammatab_srgb[r]) / 65535.f; + g = (Color::igammatab_srgb[g]) / 65535.f; + b = (Color::igammatab_srgb[b]) / 65535.f; + dst->r(i, j) = r; + dst->g(i, j) = g; + dst->b(i, j) = b; + } + + return; } - - if (mul == 1 ||(params->icm.wprim == ColorManagementParams::Primaries::DEFAULT && params->icm.will == ColorManagementParams::Illuminant::DEFAULT)) {//shortcut and speedup when no call primaries and illuminant - no gamut control...in this case be careful + + if (mul == 1 || (params->icm.wprim == ColorManagementParams::Primaries::DEFAULT && params->icm.will == ColorManagementParams::Illuminant::DEFAULT)) { //shortcut and speedup when no call primaries and illuminant - no gamut control...in this case be careful GammaValues g_a; //gamma parameters double pwr = 1.0 / static_cast(gampos); Color::calcGamma(pwr, slpos, g_a); // call to calcGamma with selected gamma and slope #ifdef _OPENMP -# pragma omp parallel for schedule(dynamic,16) if (multiThread) + # pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif + for (int y = 0; y < ch; ++y) { int x = 0; #ifdef __SSE2__ + for (; x < cw - 3; x += 4) { - STVFU(dst->r(y,x), F2V(65536.f) * gammalog(LVFU(src->r(y,x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); - STVFU(dst->g(y,x), F2V(65536.f) * gammalog(LVFU(src->g(y,x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); - STVFU(dst->b(y,x), F2V(65536.f) * gammalog(LVFU(src->b(y,x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); - } + STVFU(dst->r(y, x), F2V(65536.f) * gammalog(LVFU(src->r(y, x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); + STVFU(dst->g(y, x), F2V(65536.f) * gammalog(LVFU(src->g(y, x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); + STVFU(dst->b(y, x), F2V(65536.f) * gammalog(LVFU(src->b(y, x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); + } + #endif + for (; x < cw; ++x) { - dst->r(y,x) = 65536.f * gammalog(src->r(y,x), gampos, slpos, g_a[3], g_a[4]); - dst->g(y,x) = 65536.f * gammalog(src->g(y,x), gampos, slpos, g_a[3], g_a[4]); - dst->b(y,x) = 65536.f * gammalog(src->b(y,x), gampos, slpos, g_a[3], g_a[4]); + dst->r(y, x) = 65536.f * gammalog(src->r(y, x), gampos, slpos, g_a[3], g_a[4]); + dst->g(y, x) = 65536.f * gammalog(src->g(y, x), gampos, slpos, g_a[3], g_a[4]); + dst->b(y, x) = 65536.f * gammalog(src->b(y, x), gampos, slpos, g_a[3], g_a[4]); } } + return; } - + float redxx = params->icm.redx; float redyy = params->icm.redy; @@ -498,6 +507,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, float bluyy = params->icm.bluy; float grexx = params->icm.grex; float greyy = params->icm.grey; + float epsil = 0.0001f; if (prim == 12) {//convert datas area to xy float redgraphx = params->icm.labgridcieALow; @@ -519,11 +529,34 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, greyy = 0.55f * (gregraphy + 1.f) - 0.1f; greyy = rtengine::LIM(greyy, 0.5f, 1.f); } + //fixed crash when there is no space or too small..just a line...Possible if bx, by aligned with Gx,Gy Rx,Ry - float ac = (greyy - redyy) / (grexx - redxx); + //fix crash if user select 0 for redyy, bluyy, greyy + if (redyy == 0.f) { + redyy = epsil; + } + + if (bluyy == 0.f) { + bluyy = epsil; + } + + if (greyy == 0.f) { + greyy = epsil; + } + + //fix crash if grexx - redxx = 0 + float grered = 1.f; + grered = grexx - redxx; + + if (grered == 0.f) { + grered = epsil; + } + + float ac = (greyy - redyy) / grered; float bc = greyy - ac * grexx; float yc = ac * bluxx + bc; - if ((bluyy < yc + 0.0004f) && (bluyy > yc - 0.0004f)) {//under 0.0004 in some case crash because space too small + + if ((bluyy < yc + 0.0004f) && (bluyy > yc - 0.0004f)) { //under 0.0004 in some case crash because space too small return; } @@ -564,7 +597,6 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, } case ColorManagementParams::Primaries::ACES_P0: { - profile = "ACESp0"; break; } @@ -593,11 +625,13 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, break; } } - - if (settings->verbose && prim != 0) { - printf("prim=%i Profile Destination=%s\n", prim, profile.c_str()); - } + + if (settings->verbose && prim != 0) { + printf("prim=%i Profile Destination=%s\n", prim, profile.c_str()); + } + cmsHTRANSFORM hTransform = nullptr; + if (transform) { hTransform = transform; } else { @@ -622,7 +656,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, }; double tempv4 = 5003.; - float p[6]; //primaries + double p[6]; //primaries + double Wx = 1.0; + double Wz = 1.0; //primaries for 10 working profiles ==> output profiles if (profile == "WideGamut") { @@ -633,6 +669,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[4] = 0.1570; p[5] = 0.0180; illum = toUnderlying(ColorManagementParams::Illuminant::D50); + Wx = 0.964295676; + Wz = 0.825104603; + } else if (profile == "Adobe RGB") { p[0] = 0.6400; //Adobe primaries p[1] = 0.3300; @@ -642,6 +681,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.0600; tempv4 = 6504.; illum = toUnderlying(ColorManagementParams::Illuminant::D65); + Wx = 0.95045471; + Wz = 1.08905029; + } else if (profile == "sRGB") { p[0] = 0.6400; // sRGB primaries p[1] = 0.3300; @@ -651,6 +693,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.0600; tempv4 = 6504.; illum = toUnderlying(ColorManagementParams::Illuminant::D65); + Wx = 0.95045471; + Wz = 1.08905029; + } else if (profile == "BruceRGB") { p[0] = 0.6400; // Bruce primaries p[1] = 0.3300; @@ -660,7 +705,10 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.0600; tempv4 = 6504.; illum = toUnderlying(ColorManagementParams::Illuminant::D65); - } else if (profile == "Beta RGB") { + Wx = 0.95045471; + Wz = 1.08905029; + + } else if (profile == "Beta RGB") { p[0] = 0.6888; // Beta primaries p[1] = 0.3112; p[2] = 0.1986; @@ -668,6 +716,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[4] = 0.1265; p[5] = 0.0352; illum = toUnderlying(ColorManagementParams::Illuminant::D50); + Wx = 0.964295676; + Wz = 0.825104603; + } else if (profile == "BestRGB") { p[0] = 0.7347; // Best primaries p[1] = 0.2653; @@ -676,6 +727,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[4] = 0.1300; p[5] = 0.0350; illum = toUnderlying(ColorManagementParams::Illuminant::D50); + Wx = 0.964295676; + Wz = 0.825104603; + } else if (profile == "Rec2020") { p[0] = 0.7080; // Rec2020 primaries p[1] = 0.2920; @@ -685,6 +739,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.0460; tempv4 = 6504.; illum = toUnderlying(ColorManagementParams::Illuminant::D65); + Wx = 0.95045471; + Wz = 1.08905029; + } else if (profile == "ACESp0") { p[0] = 0.7347; // ACES P0 primaries p[1] = 0.2653; @@ -694,6 +751,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = -0.0770; tempv4 = 6004.; illum = toUnderlying(ColorManagementParams::Illuminant::D60); + Wx = 0.952646075; + Wz = 1.008825184; + } else if (profile == "ACESp1") { p[0] = 0.713; // ACES P1 primaries p[1] = 0.293; @@ -703,6 +763,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.044; tempv4 = 6004.; illum = toUnderlying(ColorManagementParams::Illuminant::D60); + Wx = 0.952646075; + Wz = 1.008825184; + } else if (profile == "ProPhoto") { p[0] = 0.7347; //ProPhoto and default primaries p[1] = 0.2653; @@ -711,8 +774,11 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[4] = 0.0366; p[5] = 0.0001; illum = toUnderlying(ColorManagementParams::Illuminant::D50); + Wx = 0.964295676; + Wz = 0.825104603; + } else if (profile == "Custom") { - p[0] = redxx; + p[0] = redxx; p[1] = redyy; p[2] = grexx; p[3] = greyy; @@ -743,11 +809,13 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, gammaParams[3] = 1. / slpos; gammaParams[5] = 0.0; gammaParams[6] = 0.0; - // printf("ga0=%f ga1=%f ga2=%f ga3=%f ga4=%f\n", ga0, ga1, ga2, ga3, ga4); + // printf("ga0=%f ga1=%f ga2=%f ga3=%f ga4=%f\n", ga0, ga1, ga2, ga3, ga4); // 7 parameters for smoother curves cmsCIExyY xyD; + Glib::ustring ills = "D50"; + switch (ColorManagementParams::Illuminant(illum)) { case ColorManagementParams::Illuminant::DEFAULT: case ColorManagementParams::Illuminant::STDA: @@ -802,55 +870,95 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, cmsWhitePointFromTemp(&xyD, tempv4); switch (ColorManagementParams::Illuminant(illum)) { - case ColorManagementParams::Illuminant::DEFAULT: - case ColorManagementParams::Illuminant::D55: + case ColorManagementParams::Illuminant::DEFAULT: { + break; + } + + case ColorManagementParams::Illuminant::D55: { + Wx = 0.956565934; + Wz = 0.920253249; + break; + } + case ColorManagementParams::Illuminant::D80: { + Wx = 0.950095542; + Wz = 1.284213976; break; } case ColorManagementParams::Illuminant::D41: { + Wx = 0.991488263; + Wz = 0.631604625; break; } case ColorManagementParams::Illuminant::D50: { xyD = {0.3457, 0.3585, 1.0}; // near LCMS values but not perfect... it's a compromise!! + Wx = 0.964295676; + Wz = 0.825104603; break; } case ColorManagementParams::Illuminant::D60: { + Wx = 0.952646075; + Wz = 1.008825184; xyD = {0.32168, 0.33767, 1.0}; break; } case ColorManagementParams::Illuminant::D65: { + Wx = 0.95045471; + Wz = 1.08905029; xyD = {0.312700492, 0.329000939, 1.0}; break; } case ColorManagementParams::Illuminant::D120: { + Wx = 0.979182; + Wz = 1.623623; xyD = {0.269669, 0.28078, 1.0}; break; } case ColorManagementParams::Illuminant::STDA: { + Wx = 1.098500393; + Wz = 0.355848714; xyD = {0.447573, 0.407440, 1.0}; ills = "stdA 2875K"; break; } case ColorManagementParams::Illuminant::TUNGSTEN_2000K: { + Wx = 1.274335; + Wz = 0.145233; xyD = {0.526591, 0.41331, 1.0}; ills = "Tungsten 2000K"; break; } case ColorManagementParams::Illuminant::TUNGSTEN_1500K: { + Wx = 1.489921; + Wz = 0.053826; xyD = {0.585703, 0.393157, 1.0}; ills = "Tungsten 1500K"; break; } } + double wprofpri[9]; + + if (gamutcontrol) { + //xyz in functiuon primaries and illuminant + Color::primaries_to_xyz(p, Wx, Wz, wprofpri); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + wprofprim[i][j] = (double) wprofpri[j * 3 + i]; + //xyz in TMatrix format + } + } + } + //D41 0.377984 0.381229 //D55 0.332424 0.347426 //D80 0.293755 0.309185 @@ -869,7 +977,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, cmsWriteTag(oprofdef, cmsSigGreenTRCTag, GammaTRC[1]); cmsWriteTag(oprofdef, cmsSigBlueTRCTag, GammaTRC[2]); - //to read XYZ values and illuminant + //to read XYZ values and illuminant if (rtengine::settings->verbose) { cmsCIEXYZ *redT = static_cast(cmsReadTag(oprofdef, cmsSigRedMatrixColumnTag)); cmsCIEXYZ *greenT = static_cast(cmsReadTag(oprofdef, cmsSigGreenMatrixColumnTag)); @@ -881,6 +989,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, } cmsFreeToneCurve(GammaTRC[0]); + if (oprofdef) { constexpr cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE | cmsFLAGS_BLACKPOINTCOMPENSATION | cmsFLAGS_GAMUTCHECK; const cmsHPROFILE iprof = ICCStore::getInstance()->getXYZProfile(); @@ -889,7 +998,10 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, lcmsMutex->unlock(); } } + if (hTransform) { + + #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif @@ -901,19 +1013,30 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, #pragma omp for schedule(dynamic, 16) nowait #endif - for (int i = 0; i < ch; ++i) { + for (int i = 0; i < ch; ++i) + { float *p = pBuf.data; + for (int j = 0; j < cw; ++j) { const float r = src->r(i, j); const float g = src->g(i, j); const float b = src->b(i, j); + float X = toxyz[0][0] * r + toxyz[0][1] * g + toxyz[0][2] * b; + 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; - *(p++) = toxyz[0][0] * r + toxyz[0][1] * g + toxyz[0][2] * b; - *(p++) = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; - *(p++) = toxyz[2][0] * r + toxyz[2][1] * g + toxyz[2][2] * b; + if (gamutcontrol) { + Color::gamutmap(X, Y, Z, wprofprim);//gamut control + } + + *(p++) = X; + *(p++) = Y; + *(p++) = Z; } + p = pBuf.data; cmsDoTransform(hTransform, p, p, cw); + for (int j = 0; j < cw; ++j) { dst->r(i, j) = *(p++) * normalize; dst->g(i, j) = *(p++) * normalize; @@ -921,10 +1044,12 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, } } } + if (!keepTransForm) { cmsDeleteTransform(hTransform); hTransform = nullptr; } + transform = hTransform; } } diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 9272c2c69..243f3595d 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -2128,7 +2128,7 @@ void ImProcFunctions::getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, 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->getImage(imgsrc->getWB(), TR_NONE, &img, pp, params->toneCurve, neutral.raw, 0); imgsrc->convertColorSpace(&img, params->icm, imgsrc->getWB()); float minVal = RT_INFINITY; float maxVal = -RT_INFINITY; @@ -8165,7 +8165,7 @@ void ImProcFunctions::calc_ref(int sp, LabImage * original, LabImage * transform deltasobelL = new LabImage(spotSi, spotSi); bool isdenoise = false; - if ((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f) && lp.denoiena) { + if ((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi || lp.nlstr > 0 || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f) && lp.denoiena) { isdenoise = true; } @@ -10891,7 +10891,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl // const int hspot = ye - ys; // const int wspot = xe - xs; - if (((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.nlstr > 0 || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f + if (((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.nlstr > 0 || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f || execmaskden || aut == 1 || aut == 2) && lp.denoiena && lp.quamet != 3) || execdenoi) { // sk == 1 ?? StopWatch Stop1("locallab Denoise called"); @@ -12540,12 +12540,31 @@ void ImProcFunctions::clarimerge(const struct local_params& lp, float &mL, float } } -void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImage * original, LabImage *transformed, int cy, int cx, int sk) +void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImage *transformed, LabImage *reserved, int cy, int cx, int sk) { - if (params->locallab.spots.at(sp).avoid && lp.islocal) { + int avoidgamut = 0; + + if (params->locallab.spots.at(sp).avoidgamutMethod == "NONE") { + avoidgamut = 0; + } else if (params->locallab.spots.at(sp).avoidgamutMethod == "LAB") { + avoidgamut = 1; + } else if (params->locallab.spots.at(sp).avoidgamutMethod == "XYZ") { + avoidgamut = 2; + } else if (params->locallab.spots.at(sp).avoidgamutMethod == "XYZREL") { + avoidgamut = 3; + } else if (params->locallab.spots.at(sp).avoidgamutMethod == "MUNS") { + avoidgamut = 4; + } + + if (avoidgamut == 0) { + return; + } + + if (avoidgamut > 0 && lp.islocal) { const float ach = lp.trans / 100.f; bool execmunsell = true; - if(params->locallab.spots.at(sp).expcie && (params->locallab.spots.at(sp).modecam == "all" || params->locallab.spots.at(sp).modecam == "jz" || params->locallab.spots.at(sp).modecam == "cam16")) { + + if (params->locallab.spots.at(sp).expcie && (params->locallab.spots.at(sp).modecam == "all" || params->locallab.spots.at(sp).modecam == "jz" || params->locallab.spots.at(sp).modecam == "cam16")) { execmunsell = false; } @@ -12556,11 +12575,18 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag {wiprof[2][0], wiprof[2][1], wiprof[2][2]} }; + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + const double wp[3][3] = {//improve precision with double + {wprof[0][0], wprof[0][1], wprof[0][2]}, + {wprof[1][0], wprof[1][1], wprof[1][2]}, + {wprof[2][0], wprof[2][1], wprof[2][2]} + }; + const float softr = params->locallab.spots.at(sp).avoidrad;//max softr = 30 - const bool muns = params->locallab.spots.at(sp).avoidmun;//Munsell control with 200 LUT + // const bool muns = params->locallab.spots.at(sp).avoidmun;//Munsell control with 200 LUT //improve precision with mint and maxt const float tr = std::min(2.f, softr); - const float mint = 0.15f - 0.06f * tr;//between 0.15f and 0.03f + const float mint = 0.15f - 0.06f * tr;//between 0.15f and 0.03f const float maxt = 0.98f + 0.008f * tr;//between 0.98f and 0.996f const bool highlight = params->toneCurve.hrenabled; @@ -12581,6 +12607,7 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag #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 @@ -12640,7 +12667,7 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag if (lp.shapmet == 0) { calcTransition(lox, loy, ach, lp, zone, localFactor); - } else /*if (lp.shapmet == 1)*/ { + } else { /*if (lp.shapmet == 1)*/ calcTransitionrect(lox, loy, ach, lp, zone, localFactor); } @@ -12675,42 +12702,103 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag sincosval.y = aa / (Chprov1 * 327.68f); sincosval.x = bb / (Chprov1 * 327.68f); } + #endif + float lnew = transformed->L[y][x]; + float anew = transformed->a[y][x]; + float bnew = transformed->b[y][x]; + Lprov1 = lnew / 327.68f; + //HH = xatan2f(bnew, anew); - Color::pregamutlab(Lprov1, HH, chr); - Chprov1 = rtengine::min(Chprov1, chr); - if(!muns) { - float R, G, B; + if (avoidgamut == 1) { //Lab correction + + Color::pregamutlab(Lprov1, HH, chr); + Chprov1 = rtengine::min(Chprov1, chr); + + float R, G, B; Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, mint, maxt);//replace for best results - } - 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; + lnew = Lprov1 * 327.68f; + anew = 327.68f * Chprov1 * sincosval.y; + bnew = 327.68f * Chprov1 * sincosval.x; + //HH = xatan2f(bnew, anew); + transformed->a[y][x] = anew; + transformed->b[y][x] = bnew; - if (needHH) { - const float Lprov2 = original->L[y][x] / 327.68f; + } else if (avoidgamut == 2 || avoidgamut == 3) { //XYZ correction + float xg, yg, zg; + const float aag = transformed->a[y][x];//anew + const float bbg = transformed->b[y][x];//bnew + float Lag = transformed->L[y][x]; + + Color::Lab2XYZ(Lag, aag, bbg, xg, yg, zg); + float x0 = xg; + float y0 = yg; + float z0 = zg; + + Color::gamutmap(xg, yg, zg, wp); + + if (avoidgamut == 3) {//0.5f arbitrary coeff + xg = xg + 0.5f * (x0 - xg); + yg = yg + 0.5f * (y0 - yg); + zg = zg + 0.5f * (z0 - zg); + } + + //Color::gamutmap(xg, yg, zg, wp);//Put XYZ in gamut wp + float aag2, bbg2; + Color::XYZ2Lab(xg, yg, zg, Lag, aag2, bbg2); + Lprov1 = Lag / 327.68f; + HH = xatan2f(bbg2, aag2);//rebuild HH in case of...absolute colorimetry + Chprov1 = std::sqrt(SQR(aag2) + SQR(bbg2)) / 327.68f; + + if (Chprov1 == 0.0f) { + sincosval.y = 1.f; + sincosval.x = 0.0f; + } else { + sincosval.y = aag2 / (Chprov1 * 327.68f); + sincosval.x = bbg2 / (Chprov1 * 327.68f); + } + + lnew = Lprov1 * 327.68f; + anew = 327.68f * Chprov1 * sincosval.y; + bnew = 327.68f * Chprov1 * sincosval.x; + transformed->a[y][x] = anew; + transformed->b[y][x] = bnew; + + } + + if (needHH && avoidgamut <= 4) {//Munsell + Lprov1 = lnew / 327.68f; + float Chprov = sqrt(SQR(anew) + SQR(bnew)) / 327.68f; + + const float Lprov2 = reserved->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; - if(execmunsell) { + const float memChprov = std::sqrt(SQR(reserved->a[y][x]) + SQR(reserved->b[y][x])) / 327.68f; + + if (execmunsell) { 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 small. + if (correctionHue != 0.f || correctlum != 0.f) { + + if (std::fabs(correctionHue) < 0.015f) { + HH += correctlum; // correct only if correct Munsell chroma very small. + } + + sincosval = xsincosf(HH + correctionHue); } - sincosval = xsincosf(HH + correctionHue); - transformed->a[y][x] = 327.68f * Chprov * sincosval.y; // apply Munsell - transformed->b[y][x] = 327.68f * Chprov * sincosval.x; + anew = 327.68f * Chprov * sincosval.y; // apply Munsell + bnew = 327.68f * Chprov * sincosval.x; + transformed->a[y][x] = anew; // apply Munsell + transformed->b[y][x] = bnew; } } } } - //Guidedfilter to reduce artifacts in transitions - if (softr != 0.f) {//soft for L a b because we change color... + //Guidedfilter to reduce artifacts in transitions : case Lab + if (softr != 0.f && avoidgamut == 1) {//soft for L a b because we change color... const float tmpblur = softr < 0.f ? -1.f / softr : 1.f + softr; const int r1 = rtengine::max(6 / sk * tmpblur + 0.5f, 1); const int r2 = rtengine::max(10 / sk * tmpblur + 0.5f, 1); @@ -12734,13 +12822,15 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag for (int y = 0; y < bh ; y++) { for (int x = 0; x < bw; x++) { ble[y][x] = transformed->L[y][x] / 32768.f; - guid[y][x] = original->L[y][x] / 32768.f; + guid[y][x] = reserved->L[y][x] / 32768.f; } } + 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 < bh; y++) { for (int x = 0; x < bw; x++) { transformed->L[y][x] = 32768.f * ble[y][x]; @@ -12757,11 +12847,13 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag blechro[y][x] = std::sqrt(SQR(transformed->b[y][x]) + SQR(transformed->a[y][x])) / 32768.f; } } + rtengine::guidedFilter(guid, blechro, blechro, r1, epsil, multiThread); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif + for (int y = 0; y < bh; y++) { for (int x = 0; x < bw; x++) { const float Chprov1 = std::sqrt(SQR(transformed->a[y][x]) + SQR(transformed->b[y][x])); @@ -12933,7 +13025,6 @@ void ImProcFunctions::NLMeans(float **img, int strength, int detail_thresh, int if(scale > 5.f) {//avoid to small values - leads to crash - but enough to evaluate noise return; } - BENCHFUN const int W = bfw; const int H = bfh; @@ -13286,7 +13377,7 @@ void ImProcFunctions::Lab_Local( 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, llcieMask, locwavCurveden, locwavdenutili); - avoidcolshi(lp, sp, original, transformed, cy, cx, sk); + //avoidcolshi(lp, sp, transformed, reserved, cy, cx, sk); const float radius = lp.rad / (sk * 1.4); //0 to 70 ==> see skip int levred; @@ -13574,7 +13665,7 @@ void ImProcFunctions::Lab_Local( //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.wavcurvedenoi || lp.noisecf > 0.f || lp.noisecc > 0.f || lp.bilat > 0.f) && lp.denoiena) { + if ((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.noiselc > 0.f || lp.wavcurvedenoi || lp.nlstr > 0 || lp.noisecf > 0.f || lp.noisecc > 0.f || lp.bilat > 0.f) && lp.denoiena) { denoiz = true; } @@ -14318,7 +14409,7 @@ void ImProcFunctions::Lab_Local( } //local denoise - if (lp.activspot && lp.denoiena && (lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f )) {//disable denoise if not used + if (lp.activspot && lp.denoiena && (lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi ||lp.nlstr > 0 || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f )) {//disable denoise if not used 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}; @@ -16793,23 +16884,36 @@ void ImProcFunctions::Lab_Local( 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; + if(lp.fullim == 2) {//limit sharpening to image dimension...no more...to avoid a long treatment + begy = 0; + begx = 0; + yEn = original->H; + xEn = original->W; + lp.lxL = lp.xc; + lp.lyT = lp.yc; + lp.ly = yEn - lp.yc; + lp.lx = xEn - lp.xc; + bfh= yEn; + bfw = xEn; + } + //printf("begy=%i begx=%i yen=%i xen=%i\n", begy, begx, yEn, xEn); + JaggedArray bufsh(bfw, bfh, true); + JaggedArray hbuffer(bfw, bfh); + JaggedArray loctemp2(bfw, bfh); + #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif @@ -16846,9 +16950,8 @@ void ImProcFunctions::Lab_Local( } - - //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); + //sharpen only square area instead of all image, but limited to image dimensions (full image) + ImProcFunctions::deconvsharpeningloc(bufsh, hbuffer, bfw, bfh, loctemp2, 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); /* float gamma = params->locallab.spots.at(sp).shargam; double pwr = 1.0 / (double) gamma;//default 3.0 - gamma Lab @@ -16864,20 +16967,20 @@ void ImProcFunctions::Lab_Local( #ifdef __SSE2__ for (; x < bfw - 3; x += 4) { STVFU(bufsh[y][x], F2V(32768.f) * gammalog(LVFU(bufsh[y][x]) / F2V(32768.f), F2V(gamma1), F2V(ts1), F2V(g_a[3]), F2V(g_a[4]))); - STVFU(loctemp[y][x], F2V(32768.f) * gammalog(LVFU(loctemp[y][x]) / F2V(32768.f), F2V(gamma1), F2V(ts1), F2V(g_a[3]), F2V(g_a[4]))); + STVFU(loctemp2[y][x], F2V(32768.f) * gammalog(LVFU(loctemp2[y][x]) / F2V(32768.f), F2V(gamma1), F2V(ts1), F2V(g_a[3]), F2V(g_a[4]))); } #endif for (; x < bfw; ++x) { bufsh[y][x] = 32768.f * gammalog(bufsh[y][x] / 32768.f, gamma1, ts1, g_a[3], g_a[4]); - loctemp[y][x] = 32768.f * gammalog(loctemp[y][x] / 32768.f, gamma1, ts1, g_a[3], g_a[4]); + loctemp2[y][x] = 32768.f * gammalog(loctemp2[y][x] / 32768.f, gamma1, ts1, g_a[3], g_a[4]); } } } - - - - + //sharpen simpleprocess + Sharp_Local(call, loctemp2, 0, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); } else { //call from dcrop.cc + JaggedArray loctemp(bfw, bfh); + float gamma1 = params->locallab.spots.at(sp).shargam; rtengine::GammaValues g_a; //gamma parameters double pwr1 = 1.0 / (double) gamma1;//default 3.0 - gamma Lab @@ -16926,13 +17029,11 @@ void ImProcFunctions::Lab_Local( } } } - - + //sharpen dcrop + Sharp_Local(call, loctemp, 0, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); } - //sharpen ellipse and transition - Sharp_Local(call, loctemp, 0, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); - + if (lp.recur) { original->CopyFrom(transformed, multiThread); float avge; @@ -16967,7 +17068,6 @@ void ImProcFunctions::Lab_Local( } - 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); /* float gamma = params->locallab.spots.at(sp).shargam; @@ -19179,7 +19279,7 @@ void ImProcFunctions::Lab_Local( // Gamut and Munsell control - very important do not deactivated to avoid crash - avoidcolshi(lp, sp, original, transformed, cy, cx, sk); + avoidcolshi(lp, sp, transformed, reserved, cy, cx, sk); } } diff --git a/rtengine/linalgebra.h b/rtengine/linalgebra.h new file mode 100644 index 000000000..32e44e147 --- /dev/null +++ b/rtengine/linalgebra.h @@ -0,0 +1,275 @@ +/* -*- C++ -*- + * This file is part of ART + * + * Copyright (c) 2022 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 { + +template +class Vec3 { +public: + Vec3() { data_[0] = data_[1] = data_[2] = T(); } + Vec3(T a, T b, T c) { data_[0] = a; data_[1] = b; data_[2] = c; } + + template + Vec3(T2 const a[3]) { data_[0] = a[0]; data_[1] = a[1]; data_[2] = a[2]; } + + Vec3 &operator=(const Vec3 &a) = default; + + template + Vec3 &operator=(T2 const a[3]) + { + data_[0] = a[0]; data_[1] = a[1]; data_[2] = a[2]; + return *this; + } + + T operator[](int i) const { return data_[i]; } + T &operator[](int i) { return data_[i]; } + operator const T *() const { return data_; } + operator T *() { return data_; } + +private: + T data_[3]; +}; + +typedef Vec3 Vec3f; + + +template +class Mat33 { +public: + Mat33() + { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + data_[i][j] = T(); + } + } + } + + Mat33(T a00, T a01, T a02, + T a10, T a11, T a12, + T a20, T a21, T a22) + { + data_[0][0] = a00; data_[0][1] = a01; data_[0][2] = a02; + data_[1][0] = a10; data_[1][1] = a11; data_[1][2] = a12; + data_[2][0] = a20; data_[2][1] = a21; data_[2][2] = a22; + } + + template + Mat33(const T2 m[3][3]) + { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + data_[i][j] = m[i][j]; + } + } + } + + Mat33 &operator=(const Mat33 &m) = default; + + template + Mat33 &operator=(const T2 m[3][3]) + { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + data_[i][j] = m[i][j]; + } + } + return *this; + } + + T const *operator[](int i) const { return data_[i]; } + T *operator[](int i) { return data_[i]; } + typedef const T(*Data)[3]; + operator Data() const { return data_; } + +private: + T data_[3][3]; +}; + + +typedef Mat33 Mat33f; + + +template +Mat33 identity() +{ + return Mat33(1, 0, 0, 0, 1, 0, 0, 0, 1); +} + + +template +Mat33 diagonal(T a, T b, T c) +{ + return Mat33(a, 0, 0, 0, b, 0, 0, 0, c); +} + + +template +Mat33 transpose(T const m[3][3]) +{ + return Mat33(m[0][0], m[1][0], m[2][0], + m[0][1], m[1][1], m[2][1], + m[0][2], m[1][2], m[2][2]); +} + +template +Mat33 transpose(const Mat33 &m) +{ + return transpose(static_cast::Data>(m)); +} + + +template +bool inverse(T const m[3][3], Mat33 &out) +{ + const T res00 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + const T res10 = m[2][0] * m[1][2] - m[1][0] * m[2][2]; + const T res20 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + const T det = m[0][0] * res00 + m[0][1] * res10 + m[0][2] * res20; + + if (std::abs(det) >= 1.0e-10) { + out[0][0] = res00 / det; + out[0][1] = (m[2][1] * m[0][2] - m[0][1] * m[2][2]) / det; + out[0][2] = (m[0][1] * m[1][2] - m[1][1] * m[0][2]) / det; + out[1][0] = res10 / det; + out[1][1] = (m[0][0] * m[2][2] - m[2][0] * m[0][2]) / det; + out[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) / det; + out[2][0] = res20 / det; + out[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) / det; + out[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) / det; + return true; + } else { + return false; + } +} + +template +Mat33 inverse(const Mat33 &m) +{ + Mat33 res; + inverse(static_cast::Data>(m), res); + return res; +} + +template +Mat33 inverse(T const m[3][3]) +{ + Mat33 res; + inverse(m, res); + return res; +} + +template +bool inverse(const Mat33 &m, Mat33 &out) +{ + return inverse(static_cast::Data>(m), out); +} + + +template +Mat33 dot_product(T const a[3][3], T const b[3][3]) +{ + Mat33 res; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + res[i][j] = 0; + + for (int k = 0; k < 3; ++k) { + res[i][j] += a[i][k] * b[k][j]; + } + } + } + + return res; +} + +template +Mat33 dot_product(const Mat33 &a, T const b[3][3]) +{ + return dot_product(static_cast::Data>(a), b); +} + +template +Mat33 dot_product(T const a[3][3], const Mat33 &b) +{ + return dot_product(a, static_cast::Data>(b)); +} + +template +Mat33 dot_product(const Mat33 &a, const Mat33 &b) +{ + return dot_product(static_cast::Data>(a), static_cast::Data>(b)); +} + + +template +Vec3 dot_product(T const a[3][3], T const b[3]) +{ + Vec3 res; + + for (int i = 0; i < 3; ++i) { + res[i] = 0; + for (int k = 0; k < 3; ++k) { + res[i] += a[i][k] * b[k]; + } + } + + return res; +} + + +template +Vec3 dot_product(const Mat33 &a, T const b[3]) +{ + return dot_product(static_cast::Data>(a), b); +} + +template +Vec3 dot_product(T const a[3][3], const Vec3 &b) +{ + return dot_product(a, static_cast(b)); +} + +template +Vec3 dot_product(const Mat33 &a, const Vec3 &b) +{ + return dot_product(static_cast::Data>(a), static_cast(b)); +} + + +template +Mat33 operator*(const Mat33 &m, T v) +{ + return Mat33(m[0][0] * v, m[0][1] * v, m[0][2] * v, + m[1][0] * v, m[1][1] * v, m[1][2] * v, + m[2][0] * v, m[2][1] * v, m[2][2] * v); +} + +template +Vec3 operator*(const Vec3 &a, T v) +{ + return Vec3(a[0] * v, a[1] * v, a[2] * v); +} + +} // namespace rtengine diff --git a/rtengine/perspectivecorrection.cc b/rtengine/perspectivecorrection.cc index 7a56ef5a8..f4428faf2 100644 --- a/rtengine/perspectivecorrection.cc +++ b/rtengine/perspectivecorrection.cc @@ -297,7 +297,7 @@ PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *sr 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->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw, 0); src->convertColorSpace(img.get(), pparams->icm, src->getWB()); neutral.commonTrans.autofill = false; // Ensures crop factor is correct. diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc index de1603f1c..1afe72c92 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -121,7 +121,7 @@ PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext double contrastThresholdDummy = 0.0; rawImage.demosaic(params.raw, false, contrastThresholdDummy); Imagefloat image(fw, fh); - rawImage.getImage (wb, TR_NONE, &image, pp, params.toneCurve, params.raw); + rawImage.getImage (wb, TR_NONE, &image, pp, params.toneCurve, params.raw, 0); rtengine::Image8 output(fw, fh); rawImage.convertColorSpace(&image, params.icm, wb); #ifdef _OPENMP diff --git a/rtengine/procevents.h b/rtengine/procevents.h index a83419559..13df614dc 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -137,7 +137,7 @@ enum ProcEventCode { EvHLComprThreshold = 107, EvResizeBoundingBox = 108, EvResizeAppliesTo = 109, - EvLAvoidColorShift = 110, + //EvLAvoidColorShift = 110, obsolete_111 = 111, // obsolete EvLRSTProtection = 112, EvDemosaicDCBIter = 113, @@ -617,7 +617,7 @@ enum ProcEventCode { Evlocallabadjblur = 587, Evlocallabbilateral = 588, Evlocallabsensiden = 589, - Evlocallabavoid = 590, + // Evlocallabavoid = 590, Evlocallabsharcontrast = 591, EvLocenacontrast = 592, Evlocallablcradius = 593, @@ -1067,7 +1067,7 @@ enum ProcEventCode { Evlocallabnlgam = 1037, Evlocallabdivgr = 1038, EvLocallabSpotavoidrad = 1039, - EvLocallabSpotavoidmun = 1040, + //EvLocallabSpotavoidmun = 1040, Evlocallabcontthres = 1041, Evlocallabnorm = 1042, Evlocallabreparw = 1043, diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 04ece8bc3..9323bd9e7 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -373,7 +373,7 @@ ToneCurveParams::ToneCurveParams() : autoexp(false), clip(0.02), hrenabled(false), - method("Blend"), + method("Coloropp"), expcomp(0), curve{ DCT_Linear @@ -390,6 +390,7 @@ ToneCurveParams::ToneCurveParams() : shcompr(50), hlcompr(0), hlbl(0), + hlth(1.0), hlcomprthresh(0), histmatching(false), fromHistMatching(false), @@ -416,6 +417,7 @@ bool ToneCurveParams::isPanningRelatedChange(const ToneCurveParams& other) const && shcompr == other.shcompr && hlcompr == other.hlcompr && hlbl == other.hlbl + && hlth == other.hlth && hlcomprthresh == other.hlcomprthresh && histmatching == other.histmatching && clampOOG == other.clampOOG); @@ -440,6 +442,7 @@ bool ToneCurveParams::operator ==(const ToneCurveParams& other) const && shcompr == other.shcompr && hlcompr == other.hlcompr && hlbl == other.hlbl + && hlth == other.hlth && hlcomprthresh == other.hlcomprthresh && histmatching == other.histmatching && fromHistMatching == other.fromHistMatching @@ -608,7 +611,7 @@ LCurveParams::LCurveParams() : brightness(0), contrast(0), chromaticity(0), - avoidcolorshift(false), + gamutmunselmethod("MUN"), rstprotection(0), lcredsk(true) { @@ -630,7 +633,7 @@ bool LCurveParams::operator ==(const LCurveParams& other) const && brightness == other.brightness && contrast == other.contrast && chromaticity == other.chromaticity - && avoidcolorshift == other.avoidcolorshift + && gamutmunselmethod == other.gamutmunselmethod && rstprotection == other.rstprotection && lcredsk == other.lcredsk; } @@ -1461,8 +1464,7 @@ ColorAppearanceParams::ColorAppearanceParams() : ybout(18), greenout(1.0), tempsc(5003), - greensc(1.0), - presetcat02(false) + greensc(1.0) { } @@ -1512,8 +1514,7 @@ bool ColorAppearanceParams::operator ==(const ColorAppearanceParams& other) cons && ybout == other.ybout && greenout == other.greenout && tempsc == other.tempsc - && greensc == other.greensc - && presetcat02 == other.presetcat02; + && greensc == other.greensc; } bool ColorAppearanceParams::operator !=(const ColorAppearanceParams& other) const @@ -2278,6 +2279,7 @@ ColorManagementParams::ColorManagementParams() : bluy(0.0001), preser(0.), fbw(false), + gamut(false), labgridcieALow(0.51763),//Prophoto red = (0.7347+0.1) * 1.81818 - 1 labgridcieBLow(-0.33582), labgridcieAHigh(-0.75163),//Prophoto blue @@ -2324,6 +2326,7 @@ bool ColorManagementParams::operator ==(const ColorManagementParams& other) cons && labgridcieWy == other.labgridcieWy && preser == other.preser && fbw == other.fbw + && gamut == other.gamut && aRendIntent == other.aRendIntent && outputProfile == other.outputProfile && outputIntent == other.outputIntent @@ -2848,6 +2851,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : structexclu(0), struc(4.0), shapeMethod("IND"), + avoidgamutMethod("MUNS"), loc{150, 150, 150, 150}, centerX(0), centerY(0), @@ -2862,13 +2866,11 @@ LocallabParams::LocallabSpot::LocallabSpot() : balanh(1.0), colorde(5.0), colorscope(30.0), - avoidrad(0.7), + avoidrad(0.), transitweak(1.0), transitgrad(0.0), hishow(false), activ(true), - avoid(false), - avoidmun(false), blwh(false), recurs(false), laplac(true), @@ -4560,6 +4562,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && structexclu == other.structexclu && struc == other.struc && shapeMethod == other.shapeMethod + && avoidgamutMethod == other.avoidgamutMethod && loc == other.loc && centerX == other.centerX && centerY == other.centerY @@ -4579,8 +4582,6 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && transitgrad == other.transitgrad && hishow == other.hishow && activ == other.activ - && avoid == other.avoid - && avoidmun == other.avoidmun && blwh == other.blwh && recurs == other.recurs && laplac == other.laplac @@ -5633,6 +5634,7 @@ bool RAWParams::PreprocessWB::operator !=(const PreprocessWB& other) const RAWParams::RAWParams() : df_autoselect(false), ff_AutoSelect(false), + ff_FromMetaData(false), ff_BlurRadius(32), ff_BlurType(getFlatFieldBlurTypeString(FlatFieldBlurType::AREA)), ff_AutoClipControl(false), @@ -5658,6 +5660,7 @@ bool RAWParams::operator ==(const RAWParams& other) const && df_autoselect == other.df_autoselect && ff_file == other.ff_file && ff_AutoSelect == other.ff_AutoSelect + && ff_FromMetaData == other.ff_FromMetaData && ff_BlurRadius == other.ff_BlurRadius && ff_BlurType == other.ff_BlurType && ff_AutoClipControl == other.ff_AutoClipControl @@ -5912,6 +5915,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->toneCurve.hrenabled, "HLRecovery", "Enabled", toneCurve.hrenabled, keyFile); saveToKeyfile(!pedited || pedited->toneCurve.method, "HLRecovery", "Method", toneCurve.method, keyFile); saveToKeyfile(!pedited || pedited->toneCurve.hlbl, "HLRecovery", "Hlbl", toneCurve.hlbl, keyFile); + saveToKeyfile(!pedited || pedited->toneCurve.hlth, "HLRecovery", "Hlth", toneCurve.hlth, keyFile); const std::map tc_mapping = { {ToneCurveMode::STD, "Standard"}, @@ -6043,7 +6047,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->labCurve.brightness, "Luminance Curve", "Brightness", labCurve.brightness, keyFile); saveToKeyfile(!pedited || pedited->labCurve.contrast, "Luminance Curve", "Contrast", labCurve.contrast, keyFile); saveToKeyfile(!pedited || pedited->labCurve.chromaticity, "Luminance Curve", "Chromaticity", labCurve.chromaticity, keyFile); - saveToKeyfile(!pedited || pedited->labCurve.avoidcolorshift, "Luminance Curve", "AvoidColorShift", labCurve.avoidcolorshift, keyFile); + saveToKeyfile(!pedited || pedited->labCurve.gamutmunselmethod, "Luminance Curve", "Gamutmunse", labCurve.gamutmunselmethod, keyFile); saveToKeyfile(!pedited || pedited->labCurve.rstprotection, "Luminance Curve", "RedAndSkinTonesProtection", labCurve.rstprotection, keyFile); saveToKeyfile(!pedited || pedited->labCurve.lcredsk, "Luminance Curve", "LCredsk", labCurve.lcredsk, keyFile); saveToKeyfile(!pedited || pedited->labCurve.lcurve, "Luminance Curve", "LCurve", labCurve.lcurve, keyFile); @@ -6144,7 +6148,6 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->colorappearance.ybout, "Color appearance", "Ybout", colorappearance.ybout, keyFile); saveToKeyfile(!pedited || pedited->colorappearance.datacie, "Color appearance", "Datacie", colorappearance.datacie, keyFile); saveToKeyfile(!pedited || pedited->colorappearance.tonecie, "Color appearance", "Tonecie", colorappearance.tonecie, keyFile); - saveToKeyfile(!pedited || pedited->colorappearance.presetcat02, "Color appearance", "Presetcat02", colorappearance.presetcat02, keyFile); const std::map ca_mapping = { {ColorAppearanceParams::TcMode::LIGHT, "Lightness"}, @@ -6346,6 +6349,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo 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->avoidgamutMethod, "Locallab", "AvoidgamutMethod_" + index_str, spot.avoidgamutMethod, 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); @@ -6365,8 +6369,6 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo 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->avoidmun, "Locallab", "Avoidmun_" + index_str, spot.avoidmun, 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); @@ -7191,6 +7193,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->icm.labgridcieWy, "Color Management", "LabGridcieWy", icm.labgridcieWy, keyFile); saveToKeyfile(!pedited || pedited->icm.preser, "Color Management", "Preser", icm.preser, keyFile); saveToKeyfile(!pedited || pedited->icm.fbw, "Color Management", "Fbw", icm.fbw, keyFile); + saveToKeyfile(!pedited || pedited->icm.gamut, "Color Management", "Gamut", icm.gamut, keyFile); saveToKeyfile(!pedited || pedited->icm.outputProfile, "Color Management", "OutputProfile", icm.outputProfile, keyFile); saveToKeyfile( !pedited || pedited->icm.aRendIntent, @@ -7484,6 +7487,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->raw.df_autoselect, "RAW", "DarkFrameAuto", raw.df_autoselect, keyFile); saveToKeyfile(!pedited || pedited->raw.ff_file, "RAW", "FlatFieldFile", relativePathIfInside(fname, fnameAbsolute, raw.ff_file), keyFile); saveToKeyfile(!pedited || pedited->raw.ff_AutoSelect, "RAW", "FlatFieldAutoSelect", raw.ff_AutoSelect, keyFile); + saveToKeyfile(!pedited || pedited->raw.ff_FromMetaData, "RAW", "FlatFieldFromMetaData", raw.ff_FromMetaData, keyFile); saveToKeyfile(!pedited || pedited->raw.ff_BlurRadius, "RAW", "FlatFieldBlurRadius", raw.ff_BlurRadius, keyFile); saveToKeyfile(!pedited || pedited->raw.ff_BlurType, "RAW", "FlatFieldBlurType", raw.ff_BlurType, keyFile); saveToKeyfile(!pedited || pedited->raw.ff_AutoClipControl, "RAW", "FlatFieldAutoClipControl", raw.ff_AutoClipControl, keyFile); @@ -7697,6 +7701,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "HLRecovery", "Enabled", pedited, toneCurve.hrenabled, pedited->toneCurve.hrenabled); assignFromKeyfile(keyFile, "HLRecovery", "Method", pedited, toneCurve.method, pedited->toneCurve.method); assignFromKeyfile(keyFile, "HLRecovery", "Hlbl", pedited, toneCurve.hlbl, pedited->toneCurve.hlbl); + assignFromKeyfile(keyFile, "HLRecovery", "Hlth", pedited, toneCurve.hlth, pedited->toneCurve.hlth); } if (keyFile.has_group("Channel Mixer")) { @@ -7868,7 +7873,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) // if Saturation == 0, should we set BWToning on? assignFromKeyfile(keyFile, "Luminance Curve", "Saturation", pedited, labCurve.chromaticity, pedited->labCurve.chromaticity); // transform AvoidColorClipping into AvoidColorShift - assignFromKeyfile(keyFile, "Luminance Curve", "AvoidColorClipping", pedited, labCurve.avoidcolorshift, pedited->labCurve.avoidcolorshift); +// assignFromKeyfile(keyFile, "Luminance Curve", "AvoidColorClipping", pedited, labCurve.avoidcolorshift, pedited->labCurve.avoidcolorshift); } else { if (keyFile.has_key("Luminance Curve", "Chromaticity")) { labCurve.chromaticity = keyFile.get_integer("Luminance Curve", "Chromaticity"); @@ -7882,7 +7887,6 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } } - assignFromKeyfile(keyFile, "Luminance Curve", "AvoidColorShift", pedited, labCurve.avoidcolorshift, pedited->labCurve.avoidcolorshift); assignFromKeyfile(keyFile, "Luminance Curve", "RedAndSkinTonesProtection", pedited, labCurve.rstprotection, pedited->labCurve.rstprotection); } @@ -7911,6 +7915,25 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Luminance Curve", "hhCurve", pedited, labCurve.hhcurve, pedited->labCurve.hhcurve); assignFromKeyfile(keyFile, "Luminance Curve", "LcCurve", pedited, labCurve.lccurve, pedited->labCurve.lccurve); assignFromKeyfile(keyFile, "Luminance Curve", "ClCurve", pedited, labCurve.clcurve, pedited->labCurve.clcurve); + if (keyFile.has_key("Luminance Curve", "Gamutmunse")) { + assignFromKeyfile(keyFile, "Luminance Curve", "Gamutmunse", pedited, labCurve.gamutmunselmethod, pedited->labCurve.gamutmunselmethod); + } else { + if (ppVersion < 303) { + if (keyFile.has_key("Luminance Curve", "AvoidColorClipping")) { + labCurve.gamutmunselmethod = + keyFile.get_boolean("Luminance Curve", "AvoidColorClipping") ? "LAB" : "NONE"; + if (pedited) { + pedited->labCurve.gamutmunselmethod = true; + } + } + } else if (keyFile.has_key("Luminance Curve", "AvoidColorShift")) { + labCurve.gamutmunselmethod = + keyFile.get_boolean("Luminance Curve", "AvoidColorShift") ? "LAB" : "NONE"; + if (pedited) { + pedited->labCurve.gamutmunselmethod = true; + } + } + } } if (keyFile.has_group("Sharpening")) { @@ -8104,7 +8127,6 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Color appearance", "Ybout", pedited, colorappearance.ybout, pedited->colorappearance.ybout); assignFromKeyfile(keyFile, "Color appearance", "Datacie", pedited, colorappearance.datacie, pedited->colorappearance.datacie); assignFromKeyfile(keyFile, "Color appearance", "Tonecie", pedited, colorappearance.tonecie, pedited->colorappearance.tonecie); - assignFromKeyfile(keyFile, "Color appearance", "Presetcat02", pedited, colorappearance.presetcat02, pedited->colorappearance.presetcat02); const std::map tc_mapping = { {"Lightness", ColorAppearanceParams::TcMode::LIGHT}, @@ -8421,6 +8443,16 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) 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); + if (keyFile.has_key("Locallab", "AvoidgamutMethod_" + index_str)) { + assignFromKeyfile(keyFile, "Locallab", "AvoidgamutMethod_" + index_str, pedited, spot.avoidgamutMethod, spotEdited.avoidgamutMethod); + } else if (keyFile.has_key("Locallab", "Avoid_" + index_str)) { + const bool avoid = keyFile.get_boolean("Locallab", "Avoid_" + index_str); + const bool munsell = keyFile.has_key("Locallab", "Avoidmun_" + index_str) && keyFile.get_boolean("Locallab", "Avoidmun_" + index_str); + spot.avoidgamutMethod = avoid ? (munsell ? "MUNS" : "LAB") : "NONE"; + if (pedited) { + spotEdited.avoidgamutMethod = true; + } + } 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); @@ -8440,8 +8472,6 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) 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", "Avoidmun_" + index_str, pedited, spot.avoidmun, spotEdited.avoidmun); 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); @@ -9456,6 +9486,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Color Management", "Bluy", pedited, icm.bluy, pedited->icm.bluy); assignFromKeyfile(keyFile, "Color Management", "Preser", pedited, icm.preser, pedited->icm.preser); assignFromKeyfile(keyFile, "Color Management", "Fbw", pedited, icm.fbw, pedited->icm.fbw); + assignFromKeyfile(keyFile, "Color Management", "Gamut", pedited, icm.gamut, pedited->icm.gamut); assignFromKeyfile(keyFile, "Color Management", "LabGridcieALow", pedited, icm.labgridcieALow, pedited->icm.labgridcieALow); assignFromKeyfile(keyFile, "Color Management", "LabGridcieBLow", pedited, icm.labgridcieBLow, pedited->icm.labgridcieBLow); assignFromKeyfile(keyFile, "Color Management", "LabGridcieAHigh", pedited, icm.labgridcieAHigh, pedited->icm.labgridcieAHigh); @@ -10130,6 +10161,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } assignFromKeyfile(keyFile, "RAW", "FlatFieldAutoSelect", pedited, raw.ff_AutoSelect, pedited->raw.ff_AutoSelect); + assignFromKeyfile(keyFile, "RAW", "FlatFieldFromMetaData", pedited, raw.ff_FromMetaData, pedited->raw.ff_FromMetaData); assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurRadius", pedited, raw.ff_BlurRadius, pedited->raw.ff_BlurRadius); assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurType", pedited, raw.ff_BlurType, pedited->raw.ff_BlurType); assignFromKeyfile(keyFile, "RAW", "FlatFieldAutoClipControl", pedited, raw.ff_AutoClipControl, pedited->raw.ff_AutoClipControl); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d730316e2..33d95a619 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -299,6 +299,7 @@ struct ToneCurveParams { int shcompr; int hlcompr; // Highlight Recovery's compression int hlbl; // Highlight Recovery's compression + double hlth; // Highlight Recovery's threshold int hlcomprthresh; // Highlight Recovery's threshold bool histmatching; // histogram matching bool fromHistMatching; @@ -376,7 +377,7 @@ struct LCurveParams { int brightness; int contrast; int chromaticity; - bool avoidcolorshift; + Glib::ustring gamutmunselmethod; double rstprotection; bool lcredsk; @@ -709,7 +710,6 @@ struct ColorAppearanceParams { double greenout; int tempsc; double greensc; - bool presetcat02; ColorAppearanceParams(); @@ -1020,6 +1020,8 @@ struct LocallabParams { int structexclu; double struc; Glib::ustring shapeMethod; // IND, SYM, INDSL, SYMSL + Glib::ustring avoidgamutMethod; // NONE, LAB, XYZ + std::vector loc; // For ellipse/rectangle: {locX, locXL, locY, locYT} int centerX; int centerY; @@ -1039,8 +1041,6 @@ struct LocallabParams { double transitgrad; bool hishow; bool activ; - bool avoid; - bool avoidmun; bool blwh; bool recurs; bool laplac; @@ -1937,6 +1937,7 @@ struct ColorManagementParams { double bluy; double preser; bool fbw; + bool gamut; double labgridcieALow; double labgridcieBLow; double labgridcieAHigh; @@ -2440,6 +2441,7 @@ struct RAWParams { Glib::ustring ff_file; bool ff_AutoSelect; + bool ff_FromMetaData; int ff_BlurRadius; Glib::ustring ff_BlurType; bool ff_AutoClipControl; diff --git a/rtengine/profilestore.cc b/rtengine/profilestore.cc index 7d937e736..f83ddd385 100644 --- a/rtengine/profilestore.cc +++ b/rtengine/profilestore.cc @@ -508,7 +508,7 @@ void ProfileStore::dumpFolderList() printf ("\n"); } -PartialProfile *ProfileStore::loadDynamicProfile (const FramesMetaData *im) +PartialProfile *ProfileStore::loadDynamicProfile (const FramesMetaData *im, const Glib::ustring& filename) { if (storeState == STORESTATE_NOTINITIALIZED) { parseProfilesOnce(); @@ -521,7 +521,7 @@ PartialProfile *ProfileStore::loadDynamicProfile (const FramesMetaData *im) } for (auto rule : dynamicRules) { - if (rule.matches (im)) { + if (rule.matches (im, filename)) { if (settings->verbose) { printf ("found matching profile %s\n", rule.profilepath.c_str()); } diff --git a/rtengine/profilestore.h b/rtengine/profilestore.h index 460facb72..e8e48c17f 100644 --- a/rtengine/profilestore.h +++ b/rtengine/profilestore.h @@ -209,7 +209,7 @@ public: void addListener (ProfileStoreListener *listener); void removeListener (ProfileStoreListener *listener); - rtengine::procparams::PartialProfile* loadDynamicProfile (const rtengine::FramesMetaData *im); + rtengine::procparams::PartialProfile* loadDynamicProfile (const rtengine::FramesMetaData *im, const Glib::ustring& filename); void dumpFolderList(); }; diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 2354f343a..8478d56ab 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -548,11 +548,18 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog CameraConstantsStore* ccs = CameraConstantsStore::getInstance(); const CameraConst *cc = ccs->get(make, model); + bool raw_crop_cc = false; + int orig_raw_width = width; + int orig_raw_height = height; if (raw_image) { - if (cc && cc->has_rawCrop()) { + orig_raw_width = raw_width; + orig_raw_height = raw_height; + + if (cc && cc->has_rawCrop(raw_width, raw_height)) { + raw_crop_cc = true; int lm, tm, w, h; - cc->get_rawCrop(lm, tm, w, h); + cc->get_rawCrop(raw_width, raw_height, lm, tm, w, h); if (isXtrans()) { shiftXtransMatrix(6 - ((top_margin - tm) % 6), 6 - ((left_margin - lm) % 6)); @@ -584,9 +591,9 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog } } - if (cc && cc->has_rawMask(0)) { - for (int i = 0; i < 8 && cc->has_rawMask(i); i++) { - cc->get_rawMask(i, mask[i][0], mask[i][1], mask[i][2], mask[i][3]); + if (cc && cc->has_rawMask(orig_raw_width, orig_raw_height, 0)) { + for (int i = 0; i < 2 && cc->has_rawMask(orig_raw_width, orig_raw_height, i); i++) { + cc->get_rawMask(orig_raw_width, orig_raw_height, i, mask[i][0], mask[i][1], mask[i][2], mask[i][3]); } } @@ -594,9 +601,10 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog free(raw_image); raw_image = nullptr; } else { - if (get_maker() == "Sigma" && cc && cc->has_rawCrop()) { // foveon images + if (get_maker() == "Sigma" && cc && cc->has_rawCrop(width, height)) { // foveon images + raw_crop_cc = true; int lm, tm, w, h; - cc->get_rawCrop(lm, tm, w, h); + cc->get_rawCrop(width, height, lm, tm, w, h); left_margin = lm; top_margin = tm; @@ -692,11 +700,12 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog printf("no constants in camconst.json exists for \"%s %s\" (relying only on dcraw defaults)\n", make, model); } + printf("raw dimensions: %d x %d\n", orig_raw_width, orig_raw_height); printf("black levels: R:%d G1:%d B:%d G2:%d (%s)\n", get_cblack(0), get_cblack(1), get_cblack(2), get_cblack(3), black_from_cc ? "provided by camconst.json" : "provided by dcraw"); printf("white levels: R:%d G1:%d B:%d G2:%d (%s)\n", get_white(0), get_white(1), get_white(2), get_white(3), white_from_cc ? "provided by camconst.json" : "provided by dcraw"); - printf("raw crop: %d %d %d %d (provided by %s)\n", left_margin, top_margin, iwidth, iheight, (cc && cc->has_rawCrop()) ? "camconst.json" : "dcraw"); + printf("raw crop: %d %d %d %d (provided by %s)\n", left_margin, top_margin, iwidth, iheight, raw_crop_cc ? "camconst.json" : "dcraw"); printf("color matrix provided by %s\n", (cc && cc->has_dcrawMatrix()) ? "camconst.json" : "dcraw"); } } diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 871267dac..2b1cd2156 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -245,11 +245,6 @@ public: return zero_is_bad == 1; } - bool isBayer() const - { - return (filters != 0 && filters != 9); - } - bool isXtrans() const { return filters == 9; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 48d7b0904..75757d325 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -39,6 +39,7 @@ #include "rawimage.h" #include "rawimagesource_i.h" #include "rawimagesource.h" +#include "rescale.h" #include "rt_math.h" #include "rtengine.h" #include "rtlensfun.h" @@ -467,6 +468,7 @@ RawImageSource::RawImageSource () { embProfile = nullptr; rgbSourceModified = false; + for (int i = 0; i < 4; ++i) { psRedBrightness[i] = psGreenBrightness[i] = psBlueBrightness[i] = 1.f; } @@ -638,6 +640,57 @@ float calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const flo return gain; } +void RawImageSource::wbMul2Camera(double &rm, double &gm, double &bm) +{ + double r = rm; + double g = gm; + double b = bm; + + auto imatrices = getImageMatrices(); + + if (imatrices) { + double rr = imatrices->cam_rgb[0][0] * r + imatrices->cam_rgb[0][1] * g + imatrices->cam_rgb[0][2] * b; + double gg = imatrices->cam_rgb[1][0] * r + imatrices->cam_rgb[1][1] * g + imatrices->cam_rgb[1][2] * b; + double bb = imatrices->cam_rgb[2][0] * r + imatrices->cam_rgb[2][1] * g + imatrices->cam_rgb[2][2] * b; + r = rr; + g = gg; + b = bb; + } + + rm = ri->get_pre_mul(0) / r; + gm = ri->get_pre_mul(1) / g; + bm = ri->get_pre_mul(2) / b; + + rm /= gm; + bm /= gm; + gm = 1.0; +} + + +void RawImageSource::wbCamera2Mul(double &rm, double &gm, double &bm) +{ + auto imatrices = getImageMatrices(); + + double r = ri->get_pre_mul(0) / rm; + double g = ri->get_pre_mul(1) / gm; + double b = ri->get_pre_mul(2) / bm; + + if (imatrices) { + double rr = imatrices->rgb_cam[0][0] * r + imatrices->rgb_cam[0][1] * g + imatrices->rgb_cam[0][2] * b; + double gg = imatrices->rgb_cam[1][0] * r + imatrices->rgb_cam[1][1] * g + imatrices->rgb_cam[1][2] * b; + double bb = imatrices->rgb_cam[2][0] * r + imatrices->rgb_cam[2][1] * g + imatrices->rgb_cam[2][2] * b; + r = rr; + g = gg; + b = bb; + } + + rm = r / g; + bm = b / g; + gm = 1.0; +} + + + void RawImageSource::getWBMults (const ColorTemp &ctemp, const RAWParams &raw, std::array& out_scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const { @@ -688,10 +741,9 @@ void RawImageSource::getWBMults (const ColorTemp &ctemp, const RAWParams &raw, s autoGainComp = camInitialGain / initialGain; } -void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw) -{ +void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw, int opposed) +{// added int opposed to force getimage to use inpaint-opposed if enable, only once MyMutex::MyLock lock(getImageMutex); - tran = defTransform (tran); // compute channel multipliers @@ -704,7 +756,9 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima gm = ri->get_pre_mul(1); bm = ri->get_pre_mul(2); } else { - ctemp.getMultipliers (r, g, b); + // ctemp.getMultipliers (r, g, b); + r = g = b = 1; + wbCamera2Mul(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; @@ -789,22 +843,52 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima int maxx = this->W, maxy = this->H, skip = pp.getSkip(); - // raw clip levels after white balance + bool iscolor = (hrp.method == "Color" || hrp.method == "Coloropp"); + const bool doClip = (chmax[0] >= clmax[0] || chmax[1] >= clmax[1] || chmax[2] >= clmax[2]) && !hrp.hrenabled && hrp.clampOOG; + bool doHr = (hrp.hrenabled && !iscolor); + if (hrp.hrenabled && iscolor) { + + if(hrp.method == "Coloropp" && opposed == 1) {//force Inpaint opposed if WB change, and opposed limited tne number to 1 + rgbSourceModified = false; + } + if (!rgbSourceModified) { + if(hrp.method == "Color") { + if (settings->verbose) { + printf ("Applying Highlight Recovery: Color propagation.\n"); + } + HLRecovery_inpaint (red, green, blue, hrp.hlbl); + } else if(hrp.method == "Coloropp" && ctemp.getTemp() >= 0) { + float s[3] = { rm, gm, bm }; + highlight_recovery_opposed(s, ctemp, hrp.hlth); + } + rgbSourceModified = true; + } + } + + // now apply the wb coefficients + if (ctemp.getTemp() >= 0) { + double r, g, b; + ctemp.getMultipliers(r, g, b); + wbMul2Camera(r, g, b); + + rm *= r; + gm *= g; + bm *= b; + } hlmax[0] = clmax[0] * rm; hlmax[1] = clmax[1] * gm; hlmax[2] = clmax[2] * bm; - const bool doClip = (chmax[0] >= clmax[0] || chmax[1] >= clmax[1] || chmax[2] >= clmax[2]) && !hrp.hrenabled && hrp.clampOOG; + const float expcomp = std::pow(2, ri->getBaselineExposure()); + rm *= expcomp; + gm *= expcomp; + bm *= expcomp; float area = skip * skip; rm /= area; gm /= area; bm /= area; - bool doHr = (hrp.hrenabled && hrp.method != "Color"); - const float expcomp = std::pow(2, ri->getBaselineExposure()); - rm *= expcomp; - gm *= expcomp; - bm *= expcomp; + #ifdef _OPENMP #pragma omp parallel if(!d1x) // omp disabled for D1x to avoid race conditions (see Issue 1088 http://code.google.com/p/rawtherapee/issues/detail?id=1088) @@ -1347,7 +1431,6 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le rif = ffm.searchFlatField(idata->getMake(), idata->getModel(), idata->getLens(), idata->getFocalLen(), idata->getFNumber(), idata->getDateTimeAsTS()); } - bool hasFlatField = (rif != nullptr); if (hasFlatField && settings->verbose) { @@ -1387,6 +1470,9 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } //FLATFIELD end + if (raw.ff_FromMetaData && isGainMapSupported()) { + applyDngGainMap(c_black, ri->getGainMaps()); + } // Always correct camera badpixels from .badpixels file const std::vector *bp = DFManager::getInstance().getBadPixels(ri->get_maker(), ri->get_model(), idata->getSerialNumber()); @@ -1694,7 +1780,6 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c rgbSourceModified = false; - if (cache) { if (!redCache) { redCache = new array2D(W, H); @@ -2393,7 +2478,6 @@ void RawImageSource::retinex(const ColorManagementParams& cmp, const RetinexPara } rgbSourceModified = false; // tricky handling for Color propagation - t5.set(); if (settings->verbose) { @@ -2439,16 +2523,17 @@ void RawImageSource::flush() void RawImageSource::HLRecovery_Global(const ToneCurveParams &hrp) { - if (hrp.hrenabled && hrp.method == "Color") { - if (!rgbSourceModified) { - if (settings->verbose) { - printf ("Applying Highlight Recovery: Color propagation...\n"); - } - - HLRecovery_inpaint (red, green, blue, hrp.hlbl); - rgbSourceModified = true; - } - } + // if (hrp.hrenabled && hrp.method == "Color") { + // if (!rgbSourceModified) { + // if (settings->verbose) { + // printf ("Applying Highlight Recovery: Color propagation...\n"); + // } +// + // HLRecovery_inpaint (red, green, blue, hrp.hlbl); +// +// rgbSourceModified = true; + // } +// } } @@ -3457,6 +3542,7 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed // very effective to reduce (or remove) the magenta, but with levels of grey ! void RawImageSource::HLRecovery_blend(float* rin, float* gin, float* bin, int width, float maxval, float* hlmax) { + constexpr int ColorCount = 3; // Transform matrixes rgb>lab and back @@ -3681,6 +3767,7 @@ void RawImageSource::HLRecovery_CIELab (float* rin, float* gin, float* bin, floa void RawImageSource::hlRecovery (const std::string &method, float* red, float* green, float* blue, int width, float* hlmax) { +// BENCHFUN if (method == "Luminance") { HLRecovery_Luminance (red, green, blue, red, green, blue, width, 65535.0); @@ -3950,12 +4037,12 @@ void RawImageSource::getRowStartEnd (int x, int &start, int &end) } } - -static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const array2D & yc, const array2D & Yc, LUTf &xxx, LUTf &yyy, LUTf &YYY, LUTu &histxy) +static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const array2D & yc, const array2D & Yc, LUTf &xxx, LUTf &yyy, LUTf &YYY, LUTu &histxy, bool purp) { - //calculate histogram x y in a range of 190 colors - //this "choice" are guided by generally colors who are in nature skin, sky, etc. in those cases "steps" are small + // calculate histogram x y in a range of 236 colors + // this "choice" are guided by generally colors who are in nature skin, sky, etc. in those cases "steps" are small // of course we can change to be more precise + // purp enable or not purple color in xyY - approximation... #ifdef _OPENMP #pragma omp parallel #endif @@ -3968,434 +4055,528 @@ static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const ar yyythr.clear(); LUTf YYYthr(YYY.getSize()); YYYthr.clear(); + // bool purp = false; #ifdef _OPENMP #pragma omp for schedule(dynamic, 4) nowait #endif - for (int y = 0; y < bfhitc ; y++) { + + for (int y = 0; y < bfhitc ; y++) + { for (int x = 0; x < bfwitc ; x++) { int nh = -1; + if (xc[y][x] < 0.12f && xc[y][x] > 0.03f && yc[y][x] > 0.1f) { // near Prophoto if (yc[y][x] < 0.2f) { nh = 0; //blue hard - } else if (yc[y][x] < 0.3f) { + } else if (yc[y][x] < 0.25f) { nh = 1; - //blue - } else if (yc[y][x] < 0.4f) { + } else if (yc[y][x] < 0.3f) { nh = 2; - + //blue + } else if (yc[y][x] < 0.35f) { + nh = 3; + } else if (yc[y][x] < 0.4f) { + nh = 4; + } else if (yc[y][x] < 0.45f) { + nh = 5; } else if (yc[y][x] < 0.5f) { //blue green - nh = 3; + nh = 6; + } else if (yc[y][x] < 0.55f) { + nh = 7; } else if (yc[y][x] < 0.6f) { - nh = 4; + nh = 8; + } else if (yc[y][x] < 0.7f) { + nh = 9; } else if (yc[y][x] < 0.82f) { //green - nh = 5; + nh = 10; } } else if (xc[y][x] < 0.24f && yc[y][x] > 0.05f) { if (yc[y][x] < 0.2f) { - nh = 6; - } else if (yc[y][x] < 0.3f) { - nh = 7; - } else if (yc[y][x] < 0.4f) { - nh = 8; - } else if (yc[y][x] < 0.5f) { - nh = 9; - } else if (yc[y][x] < 0.6f) { - nh = 10; - } else if (yc[y][x] < 0.75f) { nh = 11; - } - } else if (xc[y][x] < 0.28f && yc[y][x] > 0.1f) {//blue sky and other - if (yc[y][x] < 0.2f) { - nh = 12; } else if (yc[y][x] < 0.25f) { + nh = 12; + } else if (yc[y][x] < 0.3f) { nh = 13; - } else if (yc[y][x] < 0.29f) { + } else if (yc[y][x] < 0.35f) { nh = 14; - } else if (yc[y][x] < 0.33f) { - nh = 15; - } else if (yc[y][x] < 0.37f) { - nh = 16; } else if (yc[y][x] < 0.4f) { - nh = 17; + nh = 15; } else if (yc[y][x] < 0.45f) { - nh = 18; + nh = 16; } else if (yc[y][x] < 0.5f) { - nh = 19; + nh = 17; + } else if (yc[y][x] < 0.55f) { + nh = 18; } else if (yc[y][x] < 0.6f) { + nh = 19; + } else if (yc[y][x] < 0.67f) { nh = 20; } else if (yc[y][x] < 0.75f) { nh = 21; } - } else if (xc[y][x] < 0.31f && yc[y][x] > 0.1f) {//near neutral others + } else if (xc[y][x] < 0.28f && yc[y][x] > 0.1f) {//blue sky and other if (yc[y][x] < 0.2f) { nh = 22; - } else if (yc[y][x] < 0.24f) { + } else if (yc[y][x] < 0.23f) { nh = 23; - } else if (yc[y][x] < 0.29f) { + } else if (yc[y][x] < 0.25f) { nh = 24; - } else if (yc[y][x] < 0.32f) { + } else if (yc[y][x] < 0.27f) { nh = 25; - } else if (yc[y][x] < 0.36f) { + } else if (yc[y][x] < 0.29f) { nh = 26; - } else if (yc[y][x] < 0.4f) { + } else if (yc[y][x] < 0.31f) { nh = 27; - } else if (yc[y][x] < 0.5f) { + } else if (yc[y][x] < 0.33f) { nh = 28; - } else if (yc[y][x] < 0.7f) { + } else if (yc[y][x] < 0.35f) { nh = 29; + } else if (yc[y][x] < 0.37f) { + nh = 30; + } else if (yc[y][x] < 0.4f) { + nh = 31; + } else if (yc[y][x] < 0.45f) { + nh = 32; + } else if (yc[y][x] < 0.5f) { + nh = 33; + } else if (yc[y][x] < 0.55f) { + nh = 34; + } else if (yc[y][x] < 0.6f) { + nh = 35; + } else if (yc[y][x] < 0.67f) { + nh = 36; + } else if (yc[y][x] < 0.75f) { + nh = 37; + } + } else if (xc[y][x] < 0.31f && yc[y][x] > 0.1f) {//near neutral others + if (yc[y][x] < 0.2f) { + nh = 38; + } else if (yc[y][x] < 0.22f) { + nh = 39; + } else if (yc[y][x] < 0.24f) { + nh = 40; + } else if (yc[y][x] < 0.26f) { + nh = 41; + } else if (yc[y][x] < 0.29f) { + nh = 42; + } else if (yc[y][x] < 0.32f) { + nh = 43; + } else if (yc[y][x] < 0.36f) { + nh = 44; + } else if (yc[y][x] < 0.4f) { + nh = 45; + } else if (yc[y][x] < 0.45f) { + nh = 46; + } else if (yc[y][x] < 0.5f) { + nh = 47; + } else if (yc[y][x] < 0.6f) { + nh = 48; + } else if (yc[y][x] < 0.7f) { + nh = 49; } } else if (xc[y][x] < 0.325f && yc[y][x] > 0.1f) {//neutral 34 if (yc[y][x] < 0.2f) { - nh = 30; + nh = 50; + } else if (yc[y][x] < 0.22f) { + nh = 51; } else if (yc[y][x] < 0.24f) { - nh = 31; + nh = 52; } else if (yc[y][x] < 0.29f) { - nh = 32; + nh = 53; } else if (yc[y][x] < 0.32f) { - nh = 33; + nh = 54; } else if (yc[y][x] < 0.33f) { - nh = 34; + nh = 55; } else if (yc[y][x] < 0.335f) { - nh = 35; + nh = 56; } else if (yc[y][x] < 0.34f) { - nh = 36; + nh = 57; } else if (yc[y][x] < 0.35f) { - nh = 37; + nh = 58; } else if (yc[y][x] < 0.37f) { - nh = 38; + nh = 59; } else if (yc[y][x] < 0.4f) { - nh = 39; + nh = 60; } else if (yc[y][x] < 0.45f) { - nh = 40; + nh = 61; } else if (yc[y][x] < 0.5f) { - nh = 41; + nh = 62; } else if (yc[y][x] < 0.55f) { - nh = 42; + nh = 63; + } else if (yc[y][x] < 0.6f) { + nh = 64; + } else if (yc[y][x] < 0.65f) { + nh = 65; } else if (yc[y][x] < 0.7f) { - nh = 43; + nh = 66; } } else if (xc[y][x] < 0.335f && yc[y][x] > 0.1f) {//neutral if (yc[y][x] < 0.2f) { - nh = 44; + nh = 67; + } else if (yc[y][x] < 0.22f) { + nh = 68; } else if (yc[y][x] < 0.24f) { - nh = 45; + nh = 69; + } else if (yc[y][x] < 0.27f) { + nh = 70; } else if (yc[y][x] < 0.29f) { - nh = 46; + nh = 71; } else if (yc[y][x] < 0.32f) { - nh = 47; + nh = 72; } else if (yc[y][x] < 0.33f) { - nh = 48; + nh = 73; } else if (yc[y][x] < 0.335f) { - nh = 49; + nh = 74; } else if (yc[y][x] < 0.34f) { - nh = 50; + nh = 75; } else if (yc[y][x] < 0.345f) { - nh = 51; + nh = 76; } else if (yc[y][x] < 0.35f) { - nh = 52; + nh = 77; } else if (yc[y][x] < 0.355f) { - nh = 53; + nh = 78; } else if (yc[y][x] < 0.36f) { - nh = 54; + nh = 79; } else if (yc[y][x] < 0.37f) { - nh = 55; + nh = 80; } else if (yc[y][x] < 0.38f) { - nh = 56; + nh = 81; } else if (yc[y][x] < 0.4f) { - nh = 57; + nh = 82; } else if (yc[y][x] < 0.45f) { - nh = 58; + nh = 83; } else if (yc[y][x] < 0.5f) { - nh = 59; + nh = 84; } else if (yc[y][x] < 0.55f) { - nh = 60; + nh = 85; + } else if (yc[y][x] < 0.6f) { + nh = 86; + } else if (yc[y][x] < 0.65f) { + nh = 87; } else if (yc[y][x] < 0.7f) { - nh = 61; + nh = 88; } } else if (xc[y][x] < 0.340f && yc[y][x] > 0.1f) {//neutral if (yc[y][x] < 0.2f) { - nh = 62; + nh = 89; + } else if (yc[y][x] < 0.22f) { + nh = 90; } else if (yc[y][x] < 0.24f) { - nh = 63; + nh = 91; } else if (yc[y][x] < 0.29f) { - nh = 64; + nh = 92; } else if (yc[y][x] < 0.32f) { - nh = 65; + nh = 93; } else if (yc[y][x] < 0.325f) { - nh = 66; + nh = 94; } else if (yc[y][x] < 0.33f) { - nh = 67; + nh = 95; } else if (yc[y][x] < 0.335f) { - nh = 68; + nh = 96; } else if (yc[y][x] < 0.34f) { - nh = 69; + nh = 97; } else if (yc[y][x] < 0.345f) { - nh = 70; + nh = 98; } else if (yc[y][x] < 0.35f) { - nh = 71; + nh = 99; } else if (yc[y][x] < 0.355f) { - nh = 72; + nh = 100; } else if (yc[y][x] < 0.36f) { - nh = 73; + nh = 101; } else if (yc[y][x] < 0.37f) { - nh = 74; + nh = 102; } else if (yc[y][x] < 0.38f) { - nh = 75; + nh = 103; } else if (yc[y][x] < 0.4f) { - nh = 76; + nh = 104; } else if (yc[y][x] < 0.45f) { - nh = 77; + nh = 105; } else if (yc[y][x] < 0.5f) { - nh = 78; + nh = 106; } else if (yc[y][x] < 0.55f) { - nh = 79; + nh = 107; + } else if (yc[y][x] < 0.6f) { + nh = 108; + } else if (yc[y][x] < 0.65f) { + nh = 109; } else if (yc[y][x] < 0.7f) { - nh = 80; + nh = 110; } } else if (xc[y][x] < 0.345f && yc[y][x] > 0.1f) {//neutral 37 if (yc[y][x] < 0.2f) { - nh = 81; + nh = 111; + } else if (yc[y][x] < 0.22f) { + nh = 112; } else if (yc[y][x] < 0.24f) { - nh = 82; + nh = 113; + } else if (yc[y][x] < 0.26f) { + nh = 114; } else if (yc[y][x] < 0.29f) { - nh = 83; + nh = 115; } else if (yc[y][x] < 0.32f) { - nh = 84; + nh = 116; } else if (yc[y][x] < 0.33f) { - nh = 85; + nh = 117; } else if (yc[y][x] < 0.335f) { - nh = 86; + nh = 118; } else if (yc[y][x] < 0.34f) { - nh = 87; + nh = 119; } else if (yc[y][x] < 0.345f) { - nh = 88; + nh = 120; } else if (yc[y][x] < 0.35f) { - nh = 89; + nh = 121; } else if (yc[y][x] < 0.355f) { - nh = 90; + nh = 122; } else if (yc[y][x] < 0.36f) { - nh = 91; + nh = 123; } else if (yc[y][x] < 0.37f) { - nh = 92; + nh = 124; } else if (yc[y][x] < 0.38f) { - nh = 93; + nh = 125; } else if (yc[y][x] < 0.39f) { - nh = 94; + nh = 126; } else if (yc[y][x] < 0.4f) { - nh = 95; + nh = 127; } else if (yc[y][x] < 0.42f) { - nh = 96; + nh = 128; } else if (yc[y][x] < 0.45f) { - nh = 97; + nh = 129; } else if (yc[y][x] < 0.48f) { - nh = 98; + nh = 130; } else if (yc[y][x] < 0.5f) { - nh = 99; + nh = 131; } else if (yc[y][x] < 0.55f) { - nh = 100; + nh = 132; } else if (yc[y][x] < 0.65f) { - nh = 101; + nh = 133; } } else if (xc[y][x] < 0.355f && yc[y][x] > 0.1f) {//neutral 37 if (yc[y][x] < 0.2f) { - nh = 102; + nh = 134; + } else if (yc[y][x] < 0.22f) { + nh = 135; } else if (yc[y][x] < 0.24f) { - nh = 103; + nh = 136; + } else if (yc[y][x] < 0.26f) { + nh = 137; } else if (yc[y][x] < 0.29f) { - nh = 104; + nh = 138; } else if (yc[y][x] < 0.32f) { - nh = 105; + nh = 139; } else if (yc[y][x] < 0.33f) { - nh = 106; + nh = 140; } else if (yc[y][x] < 0.335f) { - nh = 107; + nh = 141; } else if (yc[y][x] < 0.34f) { - nh = 108; + nh = 142; } else if (yc[y][x] < 0.345f) { - nh = 109; + nh = 143; } else if (yc[y][x] < 0.35f) { - nh = 110; + nh = 144; } else if (yc[y][x] < 0.355f) { - nh = 111; + nh = 145; } else if (yc[y][x] < 0.36f) { - nh = 112; + nh = 146; } else if (yc[y][x] < 0.37f) { - nh = 113; + nh = 147; } else if (yc[y][x] < 0.38f) { - nh = 114; + nh = 148; } else if (yc[y][x] < 0.39f) { - nh = 115; + nh = 149; } else if (yc[y][x] < 0.4f) { - nh = 116; + nh = 150; } else if (yc[y][x] < 0.42f) { - nh = 117; + nh = 151; } else if (yc[y][x] < 0.45f) { - nh = 118; + nh = 152; } else if (yc[y][x] < 0.48f) { - nh = 119; + nh = 153; } else if (yc[y][x] < 0.5f) { - nh = 120; + nh = 154; } else if (yc[y][x] < 0.55f) { - nh = 121; + nh = 155; + } else if (yc[y][x] < 0.6f) { + nh = 156; } else if (yc[y][x] < 0.65f) { - nh = 122; + nh = 157; } } else if (xc[y][x] < 0.365f && yc[y][x] > 0.15f) { //0.4 if (yc[y][x] < 0.2f) { - nh = 123; + nh = 158; + } else if (yc[y][x] < 0.22f) { + nh = 159; } else if (yc[y][x] < 0.24f) { - nh = 124; + nh = 160; + } else if (yc[y][x] < 0.26f) { + nh = 161; } else if (yc[y][x] < 0.29f) { - nh = 125; + nh = 162; } else if (yc[y][x] < 0.32f) { - nh = 126; + nh = 163; } else if (yc[y][x] < 0.33f) { - nh = 127; + nh = 164; } else if (yc[y][x] < 0.34f) { - nh = 128; + nh = 165; } else if (yc[y][x] < 0.35f) { - nh = 129; + nh = 166; } else if (yc[y][x] < 0.36f) { - nh = 130; + nh = 167; } else if (yc[y][x] < 0.37f) { - nh = 131; + nh = 168; } else if (yc[y][x] < 0.38f) { - nh = 132; + nh = 169; } else if (yc[y][x] < 0.39f) { - nh = 133; + nh = 170; } else if (yc[y][x] < 0.4f) { - nh = 134; + nh = 171; } else if (yc[y][x] < 0.42f) { - nh = 135; + nh = 172; } else if (yc[y][x] < 0.45f) { - nh = 136; + nh = 173; } else if (yc[y][x] < 0.5f) { - nh = 137; + nh = 174; } else if (yc[y][x] < 0.55f) { - nh = 138; + nh = 175; } else if (yc[y][x] < 0.63f) { - nh = 139; + nh = 176; } } else if (xc[y][x] < 0.405f && yc[y][x] > 0.15f) {//45 - if (yc[y][x] < 0.2f) { - nh = 140; - } else if (yc[y][x] < 0.24f) { - nh = 141; - } else if (yc[y][x] < 0.29f) { - nh = 142; - } else if (yc[y][x] < 0.32f) { - nh = 143; - } else if (yc[y][x] < 0.34f) { - nh = 144; - } else if (yc[y][x] < 0.37f) { - nh = 145; - } else if (yc[y][x] < 0.4f) { - nh = 146; - } else if (yc[y][x] < 0.45f) { - nh = 147; - } else if (yc[y][x] < 0.5f) { - nh = 148; - } else if (yc[y][x] < 0.55f) { - nh = 149; - } else if (yc[y][x] < 0.6f) { - nh = 150; - } - } else if (xc[y][x] < 0.445f && yc[y][x] > 0.15f) {//45 - if (yc[y][x] < 0.2f) { - nh = 151; - } else if (yc[y][x] < 0.24f) { - nh = 152; - } else if (yc[y][x] < 0.29f) { - nh = 153; - } else if (yc[y][x] < 0.32f) { - nh = 154; - } else if (yc[y][x] < 0.34f) { - nh = 155; - } else if (yc[y][x] < 0.37f) { - nh = 156; - } else if (yc[y][x] < 0.4f) { - nh = 157; - } else if (yc[y][x] < 0.45f) { - nh = 158; - } else if (yc[y][x] < 0.5f) { - nh = 159; - } else if (yc[y][x] < 0.55f) { - nh = 160; - } else if (yc[y][x] < 0.58f) { - nh = 161; - } - } else if (xc[y][x] < 0.495f && yc[y][x] > 0.15f) { - if (yc[y][x] < 0.2f) { - nh = 162; - } else if (yc[y][x] < 0.24f) { - nh = 163; - } else if (yc[y][x] < 0.29f) { - nh = 164; - } else if (yc[y][x] < 0.32f) { - nh = 165; - } else if (yc[y][x] < 0.34f) { - nh = 166; - } else if (yc[y][x] < 0.37f) { - nh = 167; - } else if (yc[y][x] < 0.4f) { - nh = 168; - } else if (yc[y][x] < 0.45f) { - nh = 169; - } else if (yc[y][x] < 0.5f) { - nh = 170; - } else if (yc[y][x] < 0.55f) { - nh = 171; - } - } else if (xc[y][x] < 0.545f && yc[y][x] > 0.15f) { - if (yc[y][x] < 0.2f) { - nh = 172; - } else if (yc[y][x] < 0.24f) { - nh = 173; - } else if (yc[y][x] < 0.29f) { - nh = 174; - } else if (yc[y][x] < 0.32f) { - nh = 175; - } else if (yc[y][x] < 0.34f) { - nh = 176; - } else if (yc[y][x] < 0.37f) { + if (yc[y][x] < 0.2f && purp) {//no take into account if purp = false nh = 177; - } else if (yc[y][x] < 0.4f) { + } else if (yc[y][x] < 0.22f && purp) { nh = 178; - } else if (yc[y][x] < 0.45f) { + } else if (yc[y][x] < 0.24f && purp) { nh = 179; - } else if (yc[y][x] < 0.5f) { + } else if (yc[y][x] < 0.26f && purp) { nh = 180; - } - } else if (xc[y][x] < 0.595f && yc[y][x] > 0.15f) { - if (yc[y][x] < 0.22f) { + } else if (yc[y][x] < 0.29f && purp) { nh = 181; - } else if (yc[y][x] < 0.25f) { + } else if (yc[y][x] < 0.32f) { nh = 182; - } else if (yc[y][x] < 0.3f) { + } else if (yc[y][x] < 0.34f) { nh = 183; - } else if (yc[y][x] < 0.35f) { + } else if (yc[y][x] < 0.37f) { nh = 184; } else if (yc[y][x] < 0.4f) { nh = 185; } else if (yc[y][x] < 0.45f) { nh = 186; + } else if (yc[y][x] < 0.5f) { + nh = 187; + } else if (yc[y][x] < 0.55f) { + nh = 188; + } else if (yc[y][x] < 0.6f) { + nh = 189; + } + } else if (xc[y][x] < 0.445f && yc[y][x] > 0.15f) {//45 + if (yc[y][x] < 0.2f && purp) { + nh = 190; + } else if (yc[y][x] < 0.22f && purp) { + nh = 191; + } else if (yc[y][x] < 0.24f && purp) { + nh = 192; + } else if (yc[y][x] < 0.26f && purp) { + nh = 193; + } else if (yc[y][x] < 0.29f && purp) { + nh = 194; + } else if (yc[y][x] < 0.32f && purp) { + nh = 195; + } else if (yc[y][x] < 0.34f && purp) { + nh = 196; + } else if (yc[y][x] < 0.37f) { + nh = 197; + } else if (yc[y][x] < 0.4f) { + nh = 198; + } else if (yc[y][x] < 0.45f) { + nh = 199; + } else if (yc[y][x] < 0.5f) { + nh = 200; + } else if (yc[y][x] < 0.55f) { + nh = 201; + } else if (yc[y][x] < 0.58f) { + nh = 202; + } + } else if (xc[y][x] < 0.495f && yc[y][x] > 0.15f) { + if (yc[y][x] < 0.2f && purp) { + nh = 203; + } else if (yc[y][x] < 0.22f && purp) { + nh = 204; + } else if (yc[y][x] < 0.24f && purp) { + nh = 205; + } else if (yc[y][x] < 0.26f && purp) { + nh = 206; + } else if (yc[y][x] < 0.29f && purp) { + nh = 207; + } else if (yc[y][x] < 0.32f && purp) { + nh = 208; + } else if (yc[y][x] < 0.34f && purp) { + nh = 209; + } else if (yc[y][x] < 0.37f) { + nh = 210; + } else if (yc[y][x] < 0.4f) { + nh = 211; + } else if (yc[y][x] < 0.45f) { + nh = 212; + } else if (yc[y][x] < 0.5f) { + nh = 213; + } else if (yc[y][x] < 0.55f) { + nh = 214; + } + } else if (xc[y][x] < 0.545f && yc[y][x] > 0.15f) { + if (yc[y][x] < 0.2f && purp) { + nh = 215; + } else if (yc[y][x] < 0.22f && purp) { + nh = 216; + } else if (yc[y][x] < 0.24f && purp) { + nh = 217; + } else if (yc[y][x] < 0.26f && purp) { + nh = 218; + } else if (yc[y][x] < 0.29f && purp) { + nh = 219; + } else if (yc[y][x] < 0.32f && purp) { + nh = 220; + } else if (yc[y][x] < 0.34f && purp) { + nh = 221; + } else if (yc[y][x] < 0.37f) { + nh = 222; + } else if (yc[y][x] < 0.4f) { + nh = 223; + } else if (yc[y][x] < 0.45f) { + nh = 224; + } else if (yc[y][x] < 0.5f) { + nh = 225; + } + } else if (xc[y][x] < 0.595f && yc[y][x] > 0.15f) { + if (yc[y][x] < 0.22f) { + nh = 226; + } else if (yc[y][x] < 0.25f) { + nh = 227; + } else if (yc[y][x] < 0.3f) { + nh = 228; + } else if (yc[y][x] < 0.35f) { + nh = 229; + } else if (yc[y][x] < 0.4f) { + nh = 230; + } else if (yc[y][x] < 0.45f) { + nh = 231; } } else if (xc[y][x] < 0.65f && yc[y][x] > 0.12f) { if (yc[y][x] < 0.25f) { - nh = 187; + nh = 232; } else if (yc[y][x] < 0.3f) { - nh = 188; + nh = 233; } else if (yc[y][x] < 0.35f) { - nh = 189; + nh = 234; } else if (yc[y][x] < 0.45f) { - nh = 190; + nh = 235; } } else if (xc[y][x] < 0.75f && yc[y][x] > 0.1f) { - nh = 191; + nh = 236; //191 } + if (nh >= 0) { histxythr[nh]++; xxxthr[nh] += xc[y][x]; @@ -4404,6 +4585,7 @@ static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const ar } } } + #ifdef _OPENMP #pragma omp critical #endif @@ -4428,24 +4610,28 @@ float static studentXY(const array2D & YYcurr, const array2D & ref somcurrY += YYcurr[i][tt]; //sum observations first group } + somcurrY *= 100.f; for (int i = 0; i < Nc; i++) { somreffY += reffYY[i][tt]; //sum observations second group } + somreffY *= 100.f; for (int i = 0; i < sizcurr; i++) { somcurr2Y += SQR(YYcurr[i][tt]); //sum sqr observations first group } + somcurr2Y *= SQR(100.f); for (int i = 0; i < Nc; i++) { somreff2Y += SQR(reffYY[i][tt]); //sum sqr observations second group } + somreff2Y *= SQR(100.f); const float somsqueccurrY = somcurr2Y - SQR(somcurrY) / sizcurr; @@ -4462,19 +4648,22 @@ float static studentXY(const array2D & YYcurr, const array2D & ref //student coeeficient } -void RawImageSource::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 ColorManagementParams &cmp, const RAWParams &raw, const WBParams & wbpar) + + + +void RawImageSource::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 ColorManagementParams &cmp, const RAWParams &raw, const WBParams & wbpar, const ToneCurveParams &hrp) { /* - Copyright (c) Jacques Desmis 6 - 2018 jdesmis@gmail.com + Copyright (c) Jacques Desmis 6 - 2018 jdesmis@gmail.com, update 1 - 2023 Copyright (c) Ingo Weyrich 3 - 2020 (heckflosse67@gmx.de) - This algorithm try to find temperature correlation between 20 to 201 color between 201 spectral color and about 20 to 55 color found in the image between 192, I just found the idea in the web "correlate with chroma" instead of RGB grey point,but I don't use any algo found on the web. + This algorithm try to find temperature correlation between 20 to 80 colors between 201 spectral color and about 20 to 55 color found in the image between 236, I just found the idea in the web "correlate with chroma" instead of RGB grey point,but I don't use any algo found on the web. I have test many many algorithms to find the first one that work :) Probably (sure) there are improvement to do... I have create a table temperature with temp and white point with 118 values between 2000K and 12000K we can obviously change these values, more...with different steps - I have create a table for tint (green)with 134 values between 0.4 to 4. + I have create a table for tint (green)with 134 values between 0.4 to 4. I have create or recuparate and transformed 201 spectral colors from Colorchecker24, others color and my 468 colors target, or from web flowers, etc. with a step of 5nm, I think it is large enough. I think this value of 201 is now complete: I tested correlation with 60, 90, 100, 120, 155...better student increase with number of color, but now it seems stabilized Of course we can increase this number :) @@ -4517,17 +4706,18 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double You can change parameters in option.cc Itcwb_thres : 34 by default ==> number of color used in final algorithm - between 10 and max 55 - Itcwb_sort : false by default, can improve algorithm if true, ==> sort value in something near chroma order, instead of histogram number + Itcwb_sorted : true by default, can improve algorithm if true, ==> sort value in something near chroma order, instead of histogram number Itcwb_greenrange : 0 amplitude of green variation - between 0 to 2 Itcwb_greendeltatemp : 1 - delta temp in green iterate loop for "extra" - between 0 to 4 - Itcwb_forceextra : false - if true force algorithm "extra" ("extra" is used when camera wbsettings are wrong) to all images + Itcwb_forceextra : true by default - if true force algorithm "extra" ("extra" is used when camera wbsettings are wrong) to all images Itcwb_sizereference : 3 by default, can be set to 5 ==> size of reference color compare to size of histogram real color itcwb_delta : 1 by default can be set between 0 to 5 ==> delta temp to build histogram xy - if camera temp is not probably good itcwb_stdobserver10 : true by default - use standard observer 10°, false = standard observer 2° - itcwb_precis : 5 by default - can be set to 3 or 9 - 3 best sampling but more time...9 "old" settings - but low differences in times with 3 instead of 9 about twice time 160ms instead of 80ms for a big raw file + itcwb_precis : 3 by default - can be set to 3 or 9 - 3 best sampling but more time...9 "old" settings - but low differences in times with 3 instead of 9 about twice time 160ms instead of 80ms for a big raw file + itcwb_nopurple : true default - allow to bypass highlight recovery and inpait opposed when need flowers and not purple due to highlights... */ -// BENCHFUN - + // BENCHFUN + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix("sRGB"); const float wp[3][3] = { {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, @@ -4567,7 +4757,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {0.590, 1.f}, {0.600, 1.f}, {0.610, 1.f}, - {0.620, 1.f}, + {0.620, 1.f},//extended range {0.630, 1.f}, {0.640, 1.f}, {0.650, 1.f}, @@ -4576,7 +4766,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {0.680, 1.f}, {0.690, 1.f}, {0.700, 1.f}, - {0.714, 1.f}, + {0.714, 1.f},//usual range {0.727, 1.f}, {0.741, 1.f}, {0.755, 1.f}, @@ -4607,7 +4797,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {0.971, 1.f}, {0.980, 1.f}, {0.990, 1.f}, - {1.000, 1.f},//55 + {1.000, 1.f},//55 reference {1.010, 1.f}, {1.020, 1.f}, {1.030, 1.f}, @@ -4638,14 +4828,14 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {1.325, 1.f}, {1.350, 1.f}, {1.375, 1.f}, - {1.400, 1.f}, + {1.400, 1.f},//usual range {1.425, 1.f}, {1.450, 1.f}, {1.475, 1.f}, {1.500, 1.f}, {1.525, 1.f}, {1.550, 1.f}, - {1.575, 1.f}, + {1.575, 1.f},//extended range {1.600, 1.f}, {1.633, 1.f}, {1.666, 1.f}, @@ -4694,7 +4884,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double int end; } RangeGreen; - constexpr RangeGreen Rangestandard = {24, 86}; + constexpr RangeGreen Rangestandard = {24, 86};//usual green range constexpr RangeGreen Rangeextended = {15, 93}; const RangeGreen Rangemax = {0, N_g}; @@ -4775,7 +4965,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {4927., 0.965414, 0.809229}, {4952., 0.964908, 0.814366}, {4977., 0.964415, 0.819412}, - {5002., 0.963934, 0.824438}, + {5002., 0.963934, 0.824438},//57 reference {5027., 0.963465, 0.829444}, {5052., 0.963008, 0.834429}, {5077., 0.962563, 0.839395}, @@ -4854,10 +5044,10 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double float gmm[N_t]; float bmm[N_t]; - constexpr int siza = 192;//size of histogram + constexpr int siza = 237; //192 untill 01/2023 size of histogram - //tempref and greenref are camera wb values. - // I used them by default to select good spectral values !! + // tempref and greenref are camera wb values. + // I used them by default to select good spectral values !! but they are changed after tempref = rtengine::min(tempref, 12000.0); int repref = 0; @@ -4871,7 +5061,8 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double //calculate R G B multiplier in function illuminant and temperature const 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)); + || (ri->getSensorType() == ST_BAYER && raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO)); + for (int tt = 0; tt < N_t; ++tt) { double r, g, b; float rm, gm, bm; @@ -4921,19 +5112,27 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } ; LUTu histxy(siza); //number of values for each pair xy + histxy.clear(); LUTf xxx(siza);//for color references calculated ==> max in images "like histogram" + xxx.clear(); + LUTf yyy(siza); + yyy.clear(); + LUTf YYY(siza);//not used directly, but necessary to keep good range + YYY.clear(); bool separated = true; + int w = -1; array2D reff_spect_yy_camera(N_t, 2 * Nc + 2); + array2D reff_spect_xx_camera(N_t, 2 * Nc + 2); //here we select the good spectral color inside the 113 values @@ -4962,6 +5161,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double #ifdef _OPENMP #pragma omp parallel for #endif + for (int y = 0; y < bfh ; ++y) { for (int x = 0; x < bfw ; ++x) { const float RR = rmm[rep] * redloc[y][x]; @@ -4970,6 +5170,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double Color::rgbxyY(RR, GG, BB, xc[y][x], yc[y][x], Yc[y][x], wp); } } + //histogram xy depend of temp...but in most cases D45 ..D65.. //calculate for this image the mean values for each family of color, near histogram x y (number) //xy vary from x 0..0.77 y 0..0.82 @@ -4979,8 +5180,14 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double // step about 0.02 x 0.32 0.34 y= 0.34 0.36 skin -- sky x 0.24 0.30 y 0.28 0.32 //big step about 0.2 - histoxyY(bfhitc, bfwitc, xc, yc, Yc, xxx, yyy, YYY, histxy); - //return histogram x and y for each temp and in a range of 158 colors (siza) + bool purp = true;//if inpaint-opposed or something else enable purp + + if (hrp.hrenabled && hrp.method == "Coloropp" && settings->itcwb_nopurple == true) {//we disabled (user) with settings if image are naturally with purple (flowers...) + purp = false; + } + + histoxyY(bfhitc, bfwitc, xc, yc, Yc, xxx, yyy, YYY, histxy, purp);//purp enable, enable purple color in WB + //return histogram x and y for each temp and in a range of 235 colors (siza) } // free some memory @@ -5011,15 +5218,19 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double int n4 = 0; int n15 = 0; int n30 = 0; + //part to improve //determined the number of colors who be used after for (int nh = 0; nh < siza; nh++) { if (Wbhis[nh].histnum < 30) { n30++; //keep only existing color but avoid to small + if (Wbhis[nh].histnum < 15) { n15++; //keep only existing color but avoid to small + if (Wbhis[nh].histnum < 4) { n4++; //keep only existing color but avoid to small + if (Wbhis[nh].histnum < 1) { n1++; //keep only existing color but avoid to small } @@ -5044,7 +5255,11 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double int sizcurr2ref = sizcurrref - ntr; const int sizcu30 = sizcurrref - n30; - const int sizcu4 = rtengine::min(sizcu30, 55); + const int sizcu4 = rtengine::min(sizcu30, 55);// + + if (settings->verbose) { + printf("ntr=%i sizcurr2ref=%i sizcu30=%i sizcu4=%i\n", ntr, sizcurr2ref, sizcu30, sizcu4); + } chrom wbchro[sizcu4]; const float swpr = Txyz[repref].XX + Txyz[repref].ZZ + 1.f; @@ -5059,6 +5274,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } float estimchrom = 0.f; + //estimate chromaticity for references for (int nh = 0; nh < sizcu4; ++nh) { const float chxy = std::sqrt(SQR(xx_curref[nh][repref] - xwpr) + SQR(yy_curref[nh][repref] - ywpr)); @@ -5072,10 +5288,12 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } estimchrom /= sizcu4; - if (settings->verbose) { + + if (settings->verbose) { printf("estimchrom=%f\n", estimchrom); } - if (settings->itcwb_sort) { //sort in ascending with chroma values + + if (settings->itcwb_sorted) { //sort in ascending with chroma values std::sort(wbchro, wbchro + sizcu4, wbchro[0]); } @@ -5102,7 +5320,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double for (int nb = 1; nb <= maxnb; ++nb) { //max 5 iterations for Itcwb_thres=33, after trial 3 is good in most cases but in some cases 5 for (int i = 0; i < w; ++i) { - float mindeltaE = 100000.f; + float mindeltaE = 100000.f;//we can change this value... int kN = 0; for (int j = 0; j < Nc ; j++) { @@ -5189,7 +5407,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } } - if (extra) {//always used because I made this choice, brings better results + if (extra) {//always used if extra = true because I made this choice, brings better results struct Tempgreen { float student; int tempref; @@ -5203,14 +5421,15 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double for (int i = 0; i < N_g; ++i) {//init variables with Tgstud[i].student = 1000.f;//max value to initialize - Tgstud[i].tempref = 57;//5002K - Tgstud[i].greenref = 55;// 1.f + Tgstud[i].tempref = 57;//5002K position in the list + Tgstud[i].greenref = 55;// 1.f position in the list } const int dgoodref = rtengine::min(settings->itcwb_greendeltatemp, 4); const int scantempbeg = rtengine::max(goodref - (dgoodref + 1), 1); const int scantempend = rtengine::min(goodref + dgoodref, N_t - 1); + for (int gr = Rangegreenused.begin; gr < Rangegreenused.end; ++gr) { float minstudgr = 100000.f; int goodrefgr = 1; @@ -5246,6 +5465,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double const float BB = bmm[tt] * B_curref_reduc[i][repref]; Color::rgbxyY(RR, GG, BB, xxyycurr_reduc[2 * i][tt], xxyycurr_reduc[2 * i + 1][tt], unused, wp); } + //recalculate xy spectral now with good range of temp and green for (int j = 0; j < Nc ; ++j) { @@ -5254,6 +5474,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } int kkg = -1; + for (int i = 0; i < Nc ; ++i) { if (good_spectral[i]) { kkg++; @@ -5261,6 +5482,7 @@ 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 data //calculate student correlation const float abstudgr = std::fabs(studentXY(xxyycurr_reduc, reff_spect_xxyy, 2 * w, 2 * kkg, tt)); @@ -5269,6 +5491,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double minstudgr = abstudgr; goodrefgr = tt; } + //found the values Tgstud[gr].tempref = goodrefgr; Tgstud[gr].greenref = gr; @@ -5279,48 +5502,35 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double std::sort(Tgstud, Tgstud + N_g, Tgstud[0]); - //now search the value of green the nearest of 1 with a good student value - // I take the 3 first values - //I admit a symetrie in green coefiicient for rgb multiplier...probably not exactly true - //perhaps we can used a Snedecor test ? but why...at least we have confidence interval > 90% - int greengood; - int greengoodprov; - int goodrefprov; - float studprov; - const int goodref0 = Tgstud[0].tempref; - const int greengood0 = Tgstud[0].greenref - 55;//55 green = 1 - const float stud0 = Tgstud[0].student; - const int goodref1 = Tgstud[1].tempref; - const float stud1 = Tgstud[1].student; - const int greengood1 = Tgstud[1].greenref - 55; - const int goodref2 = Tgstud[2].tempref; - const int greengood2 = Tgstud[2].greenref - 55; - const float stud2 = Tgstud[2].student; + // now search the value of green the nearest of 1 with a good student value, I think it is a good choice, perhaps no... + // I take the 5 first values + // I admit a symetrie in green coefiicient for rgb multiplier...probably not exactly true + // perhaps we can used a Snedecor test ? but why...at least we have confidence interval > 90% + int greengood = 55; - if (std::fabs(greengood2) < std::fabs(greengood1)) { - greengoodprov = greengood2; - goodrefprov = goodref2; - studprov = stud2; - } else { - greengoodprov = greengood1; - goodrefprov = goodref1; - studprov = stud1; + int maxkgood = 5;//we can change ...to test 3, 4, 5. High values perhaps less good student, but it is a compromise... + int mingood = std::min(std::fabs(Tgstud[0].greenref - 55), std::fabs(Tgstud[1].greenref - 55)); + for (int k = 2; k < maxkgood; ++k) { + mingood = std::min(std::fabs(mingood), std::fabs(Tgstud[k].greenref - 55)); } - if (std::fabs(greengoodprov) < std::fabs(greengood0)) { - goodref = goodrefprov; - greengood = greengoodprov + 55; - studgood = studprov; + for (int k = 0; k < maxkgood ; ++k) { + if (mingood == fabs(Tgstud[k].greenref - 55)) { + greengood = Tgstud[k].greenref ; + goodref = Tgstud[k].tempref; + studgood = Tgstud[k].student;; + } + } - } else { - goodref = goodref0; - greengood = greengood0 + 55; - studgood = stud0; + if (settings->verbose) { + printf("Student_0=%f Student_k= %f\n", Tgstud[0].student, Tgstud[maxkgood - 1].student); + printf("mingood=%i greeng=%i goodref=%i stud=%f\n", mingood, greengood, goodref, (double) studgood); } tempitc = Txyz[goodref].Tem; greenitc = gree[greengood].green; + if (estimchrom < 0.025f) { float ac = -2.40f * estimchrom + 0.06f;//small empirical correction, maximum 0.06 if chroma=0 for all image, currently for very low chroma +0.02 greenitc += ac; @@ -5334,13 +5544,14 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double if (!extra) { tempitc = Txyz[goodref].Tem; } + //now we have temp green and student if (settings->verbose) { printf("ITCWB tempitc=%f gritc=%f stud=%f \n", tempitc, greenitc, studgood); } } -void RawImageSource::WBauto(double & tempref, double & greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double & avg_rm, double & avg_gm, double & avg_bm, double & tempitc, double & greenitc, float & studgood, bool & twotimes, const WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams & cmp, const RAWParams & raw) +void RawImageSource::WBauto(double & tempref, double & greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double & avg_rm, double & avg_gm, double & avg_bm, double & tempitc, double & greenitc, float & studgood, bool & twotimes, const WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams & cmp, const RAWParams & raw, const ToneCurveParams &hrp) { // BENCHFUN //auto white balance @@ -5361,8 +5572,7 @@ void RawImageSource::WBauto(double & tempref, double & greenref, array2D } tempitc = 5000.; - - ItcWB(extra, tempref, greenref, tempitc, greenitc, studgood, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, cmp, raw, wbpar); + ItcWB(extra, tempref, greenref, tempitc, greenitc, studgood, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, cmp, raw, wbpar, hrp); } } @@ -5370,15 +5580,18 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int { // BENCHFUN //used by auto WB local to calculate red, green, blue in local region + int precision = 5; + if (settings->itcwb_precis == 5) { precision = 5; } else if (settings->itcwb_precis < 5) { - precision = 3; + precision = 3; } else if (settings->itcwb_precis > 5) { precision = 9; } + const int bfw = W / precision + ((W % precision) > 0 ? 1 : 0);// 5 arbitrary value can be change to 3 or 9 ; const int bfh = H / precision + ((H % precision) > 0 ? 1 : 0); @@ -5401,6 +5614,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int #ifdef _OPENMP #pragma omp parallel for reduction(+:avgL, nn) #endif + for (int i = 0; i < H; i ++) { for (int j = 0; j < W; j++) { const float LL = 0.299f * red[i][j] + 0.587f * green[i][j] + 0.114f * blue[i][j]; @@ -5408,6 +5622,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int nn++; } } + avgL /= nn; double vari = 0.f; @@ -5416,6 +5631,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int #ifdef _OPENMP #pragma omp parallel for reduction(+:vari, mm) #endif + for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) { const float LL = 0.299f * red[i][j] + 0.587f * green[i][j] + 0.114f * blue[i][j]; @@ -5429,8 +5645,10 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int #ifdef _OPENMP #pragma omp parallel for #endif + for (int i = 0; i < bfh; ++i) { const int ii = i * precision; + if (ii < H) { for (int j = 0, jj = 0; j < bfw; ++j, jj += precision) { redloc[i][j] = red[ii][jj] * multip; @@ -5441,7 +5659,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int } } -void RawImageSource::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 WBParams & wbpar, const ColorManagementParams & cmp, const RAWParams & raw) +void RawImageSource::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 WBParams & wbpar, const ColorManagementParams & cmp, const RAWParams & raw, const ToneCurveParams &hrp) { // BENCHFUN constexpr double clipHigh = 64000.0; @@ -5456,6 +5674,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref double avg_b = 0; int rn = 0, gn = 0, bn = 0; double avg_rm, avg_gm, avg_bm; + if (wbpar.method == "autold") { if (fuji) { for (int i = 32; i < H - 32; i++) { @@ -5465,7 +5684,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref for (int j = start; j < end; j++) { if (ri->getSensorType() != ST_BAYER) { - double dr = CLIP(initialGain * (rawData[i][3 * j] )); + double dr = CLIP(initialGain * (rawData[i][3 * j])); double dg = CLIP(initialGain * (rawData[i][3 * j + 1])); double db = CLIP(initialGain * (rawData[i][3 * j + 2])); @@ -5504,18 +5723,18 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref if (ri->getSensorType() == ST_FUJI_XTRANS) { const double compval = clipHigh / initialGain; #ifdef _OPENMP - #pragma omp parallel + #pragma omp parallel #endif { double avg_c[3] = {0.0}; int cn[3] = {0}; #ifdef _OPENMP - #pragma omp for schedule(dynamic,16) nowait + #pragma omp for schedule(dynamic,16) nowait #endif for (int i = 32; i < H - 32; i++) { for (int j = 32; j < W - 32; j++) { - // each loop read 1 rgb triplet value + // each loop read 1 rgb triplet value double d = rawData[i][j]; if (d > compval) { @@ -5529,7 +5748,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref } #ifdef _OPENMP - #pragma omp critical + #pragma omp critical #endif { avg_r += avg_c[0]; @@ -5546,9 +5765,9 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref } else { for (int i = 32; i < H - 32; i++) for (int j = 32; j < W - 32; j++) { - // each loop read 1 rgb triplet value + // each loop read 1 rgb triplet value - double dr = CLIP(initialGain * (rawData[i][3 * j] )); + double dr = CLIP(initialGain * (rawData[i][3 * j])); double dg = CLIP(initialGain * (rawData[i][3 * j + 1])); double db = CLIP(initialGain * (rawData[i][3 * j + 2])); @@ -5566,7 +5785,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref bn = rn; } } else { - //determine GRBG coset; (ey,ex) is the offset of the R subarray + //determine GRBG coset; (ey,ex) is the offset of the R subarray int ey, ex; if (ri->ISGREEN(0, 0)) { //first pixel is G @@ -5589,12 +5808,12 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref const double compval = clipHigh / initialGain; #ifdef _OPENMP - #pragma omp parallel for reduction(+:avg_r,avg_g,avg_b,rn,gn,bn) schedule(dynamic,8) + #pragma omp parallel for reduction(+:avg_r,avg_g,avg_b,rn,gn,bn) schedule(dynamic,8) #endif for (int i = 32; i < H - 32; i += 2) for (int j = 32; j < W - 32; j += 2) { - //average each Bayer quartet component individually if non-clipped + //average each Bayer quartet component individually if non-clipped double d[2][2]; d[0][0] = rawData[i][j]; d[0][1] = rawData[i][j + 1]; @@ -5633,17 +5852,18 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref if (wbpar.method == "autitcgreen") { bool twotimes = false; int precision = 5; + if (settings->itcwb_precis == 5) { precision = 5; } else if (settings->itcwb_precis < 5) { - precision = 3; + precision = 3; } else if (settings->itcwb_precis > 5) { precision = 9; } - + const int bfw = W / precision + ((W % precision) > 0 ? 1 : 0);// 5 arbitrary value can be change to 3 or 9 ; const int bfh = H / precision + ((H % precision) > 0 ? 1 : 0); - WBauto(tempref, greenref, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, tempitc, greenitc, studgood, twotimes, wbpar, begx, begy, yEn, xEn, cx, cy, cmp, raw); + WBauto(tempref, greenref, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, tempitc, greenitc, studgood, twotimes, wbpar, begx, begy, yEn, xEn, cx, cy, cmp, raw, hrp); } redloc(0, 0); @@ -5651,7 +5871,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref blueloc(0, 0); if (settings->verbose) { - printf ("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn)); + printf("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn)); } if (wbpar.method == "autitcgreen") { @@ -5670,7 +5890,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref } -void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) +void RawImageSource::getAutoWBMultipliers(double &rm, double &gm, double &bm) { // BENCHFUN constexpr double clipHigh = 64000.0; @@ -5707,7 +5927,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) for (int j = start; j < end; j++) { if (ri->getSensorType() != ST_BAYER) { - double dr = CLIP(initialGain * (rawData[i][3 * j] )); + double dr = CLIP(initialGain * (rawData[i][3 * j])); double dg = CLIP(initialGain * (rawData[i][3 * j + 1])); double db = CLIP(initialGain * (rawData[i][3 * j + 2])); @@ -5790,7 +6010,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) for (int j = 32; j < W - 32; j++) { // each loop read 1 rgb triplet value - double dr = CLIP(initialGain * (rawData[i][3 * j] )); + double dr = CLIP(initialGain * (rawData[i][3 * j])); double dg = CLIP(initialGain * (rawData[i][3 * j + 1])); double db = CLIP(initialGain * (rawData[i][3 * j + 2])); @@ -5872,7 +6092,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) } if (settings->verbose) { - printf ("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn)); + printf("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn)); } // return ColorTemp (pow(avg_r/rn, 1.0/6.0)*img_r, pow(avg_g/gn, 1.0/6.0)*img_g, pow(avg_b/bn, 1.0/6.0)*img_b); @@ -6259,6 +6479,36 @@ void RawImageSource::getRawValues(int x, int y, int rotate, int &R, int &G, int } } +bool RawImageSource::isGainMapSupported() const { + return ri->isGainMapSupported(); +} + +void RawImageSource::applyDngGainMap(const float black[4], const std::vector &gainMaps) { + // now we can apply each gain map to raw_data + array2D mvals[2][2]; + for (auto &m : gainMaps) { + mvals[m.Top & 1][m.Left & 1](m.MapPointsH, m.MapPointsV, m.MapGain.data()); + } + + // now we assume, col_scale and row scale is the same for all maps + const float col_scale = float(gainMaps[0].MapPointsH-1) / float(W); + const float row_scale = float(gainMaps[0].MapPointsV-1) / float(H); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 16) +#endif + for (std::size_t y = 0; y < static_cast(H); ++y) { + const float rowBlack[2] = {black[FC(y,0)], black[FC(y,1)]}; + const float ys = y * row_scale; + float xs = 0.f; + for (std::size_t x = 0; x < static_cast(W); ++x, xs += col_scale) { + const float f = getBilinearValue(mvals[y & 1][x & 1], xs, ys); + const float b = rowBlack[x & 1]; + rawData[y][x] = rtengine::max((rawData[y][x] - b) * f + b, 0.f); + } + } +} + void RawImageSource::cleanup () { delete phaseOneIccCurve; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 41a400dd9..fabea5ffc 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -24,6 +24,7 @@ #include "array2D.h" #include "colortemp.h" +#include "dnggainmap.h" #include "iimage.h" #include "imagesource.h" #include "procparams.h" @@ -111,7 +112,7 @@ protected: 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); + 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, const procparams::ToneCurveParams &hrp); unsigned FC(int row, int col) const; inline void getRowStartEnd (int x, int &start, int &end); @@ -140,12 +141,12 @@ public: void processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, array2D &rawData, const float black[4]); void copyOriginalPixels(const procparams::RAWParams &raw, RawImage *ri, const RawImage *riDark, RawImage *riFlatFile, array2D &rawData ); void scaleColors (int winx, int winy, int winw, int winh, const procparams::RAWParams &raw, array2D &rawData); // raw for cblack - void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) override; - 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 WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override; + 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, const procparams::ToneCurveParams &hrp) 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; + void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw, int opposed) override; eSensorType getSensorType () const override; bool isMono () const override; ColorTemp getWB () const override @@ -177,6 +178,8 @@ public: return true; } + bool isGainMapSupported() const override; + void setProgressListener (ProgressListener* pl) override { plistener = pl; @@ -196,7 +199,8 @@ public: 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, int blur); - static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval); + void highlight_recovery_opposed(float scale_mul[3], const ColorTemp &wb, float gainth); + static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval); static void HLRecovery_CIELab (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval, double cam[3][3], double icam[3][3]); static void HLRecovery_blend (float* rin, float* gin, float* bin, int width, float maxval, float* hlmax); static void init (); @@ -304,6 +308,10 @@ protected: void vflip (Imagefloat* im); void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override; void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) override; + void applyDngGainMap(const float black[4], const std::vector &gainMaps); +public: + void wbMul2Camera(double &rm, double &gm, double &bm) override; + void wbCamera2Mul(double &rm, double &gm, double &bm) override; }; } diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index d45283c38..eb4a3f888 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -94,7 +94,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { HDR, // EvCACorr, ALLNORAW, // EvHREnabled, 0, // EvHRAmount : obsolete, - ALLNORAW, // EvHRMethod, + ALLNORAW|M_RAW, // EvHRMethod, DEMOSAIC, // EvWProfile, OUTPUTPROFILE, // EvOProfile, ALLNORAW, // EvIProfile, @@ -1185,8 +1185,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { AUTOEXP, //Evlocallabforcebw AUTOEXP, //Evlocallabsigjz AUTOEXP, //Evlocallabsigq - AUTOEXP //Evlocallablogcie - + AUTOEXP //Evlocallablogcie }; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index b9fc916f6..989ca3354 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -493,7 +493,7 @@ class ImageTypeListener { public: virtual ~ImageTypeListener() = default; - virtual void imageTypeChanged(bool isRaw, bool isBayer, bool isXtrans, bool is_Mono = false) = 0; + virtual void imageTypeChanged(bool isRaw, bool isBayer, bool isXtrans, bool is_Mono = false, bool isGainMapSupported = false) = 0; }; class AutoContrastListener diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 86f1c1372..84c33a734 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -349,7 +349,7 @@ Image8 *load_inspector_mode(const Glib::ustring &fname, RawMetaDataLocation &rml PreviewProps pp(0, 0, w, h, 1); Imagefloat tmp(w, h); - src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw); + src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw, 0); src.convertColorSpace(&tmp, neutral.icm, src.getWB()); Image8 *img = new Image8(w, h); diff --git a/rtengine/settings.h b/rtengine/settings.h index bc49a2281..6e787a112 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -44,6 +44,7 @@ public: bool monitorBPC; ///< Black Point Compensation for the Labimage->Monitor transform (directly, i.e. not soft-proofing and no WCS in between) bool autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile bool autocielab; + bool observer10; bool rgbcurveslumamode_gamut;// controls gamut enforcement for RGB curves in lumamode bool verbose; Glib::ustring darkFramesPath; ///< The default directory for dark frames @@ -83,6 +84,7 @@ 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 + Glib::ustring lensfunDbBundleDirectory; int cropsleep; double reduchigh; double reduclow; @@ -93,7 +95,7 @@ public: // bool showtooltip; int itcwb_thres; - bool itcwb_sort; + bool itcwb_sorted; int itcwb_greenrange; int itcwb_greendeltatemp; bool itcwb_forceextra; @@ -101,6 +103,7 @@ public: int itcwb_delta; bool itcwb_stdobserver10; int itcwb_precis; + bool itcwb_nopurple; //wavelet levels double edghi; double edglo; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 6e75635cf..5de3b08b0 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -261,7 +261,7 @@ private: pl->setProgress(0.40); } - imgsrc->HLRecovery_Global(params.toneCurve); + // imgsrc->HLRecovery_Global(params.toneCurve); if (pl) { @@ -372,7 +372,7 @@ private: int beg_tileW = wcr * tileWskip + tileWskip / 2.f - crW / 2.f; int beg_tileH = hcr * tileHskip + tileHskip / 2.f - crH / 2.f; PreviewProps ppP(beg_tileW, beg_tileH, crW, crH, skipP); - imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw); + imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0); //baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve); // we only need image reduced to 1/4 here @@ -596,7 +596,7 @@ private: for (int wcr = 0; wcr <= 2; wcr++) { for (int hcr = 0; hcr <= 2; hcr++) { PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1); - imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw); + imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0); //baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve); @@ -756,7 +756,7 @@ private: } baseImg = new Imagefloat(fw, fh); - imgsrc->getImage(currWB, tr, baseImg, pp, params.toneCurve, params.raw); + imgsrc->getImage(currWB, tr, baseImg, pp, params.toneCurve, params.raw, 1); if (pl) { pl->setProgress(0.50); @@ -924,6 +924,14 @@ private: //ImProcFunctions ipf (¶ms, true); ImProcFunctions &ipf = * (ipf_p.get()); + for (int sp = 0; sp < (int)params.locallab.spots.size(); sp++) { + if(params.locallab.spots.at(sp).expsharp && params.dirpyrequalizer.cbdlMethod == "bef") { + if(params.locallab.spots.at(sp).shardamping < 1) { + params.locallab.spots.at(sp).shardamping = 1; + } + } + } + if (params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) { const int W = baseImg->getWidth(); const int H = baseImg->getHeight(); diff --git a/rtengine/spot.cc b/rtengine/spot.cc index 5ed090712..09186a399 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -459,7 +459,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s } } - imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw); + imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw, 0); if (cmp) { imgsrc->convertColorSpace(srcImage, *cmp, currWB); } @@ -479,7 +479,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s dstImage->b(y, x) = 60000.f; } } - imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw); + imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw, 0); if (cmp) { imgsrc->convertColorSpace(dstImage, *cmp, currWB); } diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 8cb8fa792..a3f2502f0 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -193,7 +193,7 @@ int StdImageSource::load (const Glib::ustring &fname) return 0; } -void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw) +void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw, int opposed) { // the code will use OpenMP as of now. @@ -311,11 +311,11 @@ void StdImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) } } -void StdImageSource::WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams &cmp, const RAWParams &raw) +void StdImageSource::WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams &cmp, const RAWParams &raw, const ToneCurveParams &hrp) { } -void StdImageSource::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 WBParams & wbpar, const ColorManagementParams &cmp, const RAWParams &raw) +void StdImageSource::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 WBParams & wbpar, const ColorManagementParams &cmp, const RAWParams &raw, const ToneCurveParams &hrp) { if (redAWBMul != -1.) { rm = redAWBMul; @@ -324,7 +324,7 @@ void StdImageSource::getAutoWBMultipliersitc(double &tempref, double &greenref, return; } - img->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc,studgood, begx, begy, yEn, xEn, cx, cy, bf_h, bf_w, rm, gm, bm, params->wb, params->icm, params->raw); + img->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc,studgood, begx, begy, yEn, xEn, cx, cy, bf_h, bf_w, rm, gm, bm, params->wb, params->icm, params->raw, params->toneCurve); redAWBMul = rm; greenAWBMul = gm; @@ -367,6 +367,20 @@ void StdImageSource::flush() { img->allocate(0, 0); }; +void StdImageSource::wbMul2Camera(double &rm, double &gm, double &bm) +{ + rm = 1.0 / rm; + gm = 1.0 / gm; + bm = 1.0 / bm; +} + + +void StdImageSource::wbCamera2Mul(double &rm, double &gm, double &bm) +{ + rm = 1.0 / rm; + gm = 1.0 / gm; + bm = 1.0 / bm; +} } diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 9b95fe34e..90c4be654 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -58,7 +58,7 @@ public: 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 getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw, int opposed) 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 { @@ -66,8 +66,8 @@ public: } void getAutoWBMultipliers (double &rm, double &gm, double &bm) override; ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) override; - void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) override; - 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 WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override; + 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, const procparams::ToneCurveParams &hrp) override; eSensorType getSensorType() const override {return ST_NONE;} bool isMono() const override {return false;} @@ -100,6 +100,11 @@ public: return false; } + bool isGainMapSupported() const override + { + return false; + } + void setProgressListener (ProgressListener* pl) override { plistener = pl; @@ -118,6 +123,8 @@ public: void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override { R = G = B = 0;} + void wbMul2Camera(double &rm, double &gm, double &bm) override; + void wbCamera2Mul(double &rm, double &gm, double &bm) override; void flush () override; void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) override {}; diff --git a/rtengine/winutils.h b/rtengine/winutils.h new file mode 100644 index 000000000..757849dd1 --- /dev/null +++ b/rtengine/winutils.h @@ -0,0 +1,124 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 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 + +#ifdef WIN32 + +#include +#include + +#include "noncopyable.h" + + +/** + * Wrapper for pointers to memory allocated by HeapAlloc. + * + * Memory is automatically freed when the object goes out of scope. + */ +template +class WinHeapPtr : public rtengine::NonCopyable +{ +private: + const T ptr; + +public: + WinHeapPtr() = delete; + + /** Allocates the specified number of bytes in the process heap. */ + explicit WinHeapPtr(SIZE_T bytes): ptr(static_cast(HeapAlloc(GetProcessHeap(), 0, bytes))) {}; + + ~WinHeapPtr() + { + // HeapFree does a null check. + HeapFree(GetProcessHeap(), 0, static_cast(ptr)); + } + + T operator ->() const + { + return ptr; + } + + operator T() const + { + return ptr; + } +}; + +/** + * Wrapper for HLOCAL pointers to memory allocated by LocalAlloc. + * + * Memory is automatically freed when the object goes out of scope. + */ +template +class WinLocalPtr : public rtengine::NonCopyable +{ +private: + const T ptr; + +public: + WinLocalPtr() = delete; + + /** Wraps a raw pointer. */ + WinLocalPtr(T pointer): ptr(pointer) {}; + + ~WinLocalPtr() + { + // LocalFree does a null check. + LocalFree(static_cast(ptr)); + } + + T operator ->() const + { + return ptr; + } + + operator T() const + { + return ptr; + } +}; + +/** + * Wrapper for HANDLEs. + * + * Handles are automatically closed when the object goes out of scope. + */ +class WinHandle : public rtengine::NonCopyable +{ +private: + const HANDLE handle; + +public: + WinHandle() = delete; + + /** Wraps a HANDLE. */ + WinHandle(HANDLE handle): handle(handle) {}; + + ~WinHandle() + { + CloseHandle(handle); + } + + operator HANDLE() const + { + return handle; + } +}; + +#endif diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 7976bdc7a..7f5c2dfe3 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -62,6 +62,7 @@ set(NONCLISOURCEFILES exiffiltersettings.cc exifpanel.cc exportpanel.cc + externaleditorpreferences.cc extprog.cc fattaltonemap.cc filebrowser.cc @@ -134,6 +135,7 @@ set(NONCLISOURCEFILES retinex.cc rgbcurves.cc rotate.cc + rtappchooserdialog.cc rtimage.cc rtscalable.cc rtsurface.cc @@ -160,6 +162,7 @@ set(NONCLISOURCEFILES thumbnail.cc tonecurve.cc toolbar.cc + toollocationpref.cc toolpanel.cc toolpanelcoord.cc vibrance.cc diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 463ac7cde..20dd9154c 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -264,6 +264,7 @@ bool BatchQueue::saveBatchQueue () << saveFormat.tiffBits << '|' << (saveFormat.tiffFloat ? 1 : 0) << '|' << saveFormat.tiffUncompressed << '|' << saveFormat.saveParams << '|' << entry->forceFormatOpts << '|' << entry->fast_pipeline << '|' + << saveFormat.bigTiff << '|' << std::endl; } } @@ -331,6 +332,7 @@ bool BatchQueue::loadBatchQueue () const auto saveParams = nextIntOr (options.saveFormat.saveParams); const auto forceFormatOpts = nextIntOr (options.forceFormatOpts); const auto fast = nextIntOr(false); + const auto bigTiff = nextIntOr (options.saveFormat.bigTiff); rtengine::procparams::ProcParams pparams; @@ -370,6 +372,7 @@ bool BatchQueue::loadBatchQueue () saveFormat.tiffBits = tiffBits; saveFormat.tiffFloat = tiffFloat == 1; saveFormat.tiffUncompressed = tiffUncompressed != 0; + saveFormat.bigTiff = bigTiff != 0; saveFormat.saveParams = saveParams != 0; entry->forceFormatOpts = forceFormatOpts != 0; } else { @@ -693,7 +696,13 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) int err = 0; if (saveFormat.format == "tif") { - err = img->saveAsTIFF (fname, saveFormat.tiffBits, saveFormat.tiffFloat, saveFormat.tiffUncompressed); + err = img->saveAsTIFF ( + fname, + saveFormat.tiffBits, + saveFormat.tiffFloat, + saveFormat.tiffUncompressed, + saveFormat.bigTiff + ); } else if (saveFormat.format == "png") { err = img->saveAsPNG (fname, saveFormat.pngBits); } else if (saveFormat.format == "jpg") { diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc index 334dc529f..15380d459 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -35,7 +35,7 @@ bool BatchQueueEntry::iconsLoaded(false); std::shared_ptr BatchQueueEntry::savedAsIcon(std::shared_ptr(nullptr)); BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, int prevw, int prevh, Thumbnail* thm, bool overwrite) : - ThumbBrowserEntryBase(fname), + ThumbBrowserEntryBase(fname, thm), opreview(nullptr), origpw(prevw), origph(prevh), @@ -202,6 +202,9 @@ std::tuple BatchQueueEntry::getToolTip (int x, int y) const if (saveFormat.tiffUncompressed) { tooltip += Glib::ustring::compose("\n%1", M("SAVEDLG_TIFFUNCOMPRESSED")); } + if (saveFormat.bigTiff) { + tooltip += Glib::ustring::compose("\n%1", M("SAVEDLG_BIGTIFF")); + } } } } diff --git a/rtgui/bayerpreprocess.cc b/rtgui/bayerpreprocess.cc index 793496b5f..e8b965736 100644 --- a/rtgui/bayerpreprocess.cc +++ b/rtgui/bayerpreprocess.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -BayerPreProcess::BayerPreProcess() : FoldableToolPanel(this, "bayerpreprocess", M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar) +const Glib::ustring BayerPreProcess::TOOL_NAME = "bayerpreprocess"; + +BayerPreProcess::BayerPreProcess() : FoldableToolPanel(this, TOOL_NAME, M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar) { auto m = ProcEventMapper::getInstance(); EvLineDenoiseDirection = m->newEvent(DARKFRAME, "HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION"); diff --git a/rtgui/bayerpreprocess.h b/rtgui/bayerpreprocess.h index 16b469626..8b5f8d981 100644 --- a/rtgui/bayerpreprocess.h +++ b/rtgui/bayerpreprocess.h @@ -37,6 +37,7 @@ protected: rtengine::ProcEvent EvPDAFLinesFilter; public: + static const Glib::ustring TOOL_NAME; BayerPreProcess (); diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 4d1657a47..e7e038e52 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -28,9 +28,10 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring BayerProcess::TOOL_NAME = "bayerprocess"; BayerProcess::BayerProcess () : - FoldableToolPanel(this, "bayerprocess", M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar), + FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar), oldMethod(-1) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index b9c63e9b2..00a5c8aac 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -76,6 +76,7 @@ protected: rtengine::ProcEvent EvDemosaicPixelshiftDemosaicMethod; rtengine::ProcEvent EvPixelshiftAverage; public: + static const Glib::ustring TOOL_NAME; BayerProcess (); ~BayerProcess () override; diff --git a/rtgui/bayerrawexposure.cc b/rtgui/bayerrawexposure.cc index 157abc2cf..834384a91 100644 --- a/rtgui/bayerrawexposure.cc +++ b/rtgui/bayerrawexposure.cc @@ -26,7 +26,9 @@ using namespace rtengine; using namespace rtengine::procparams; -BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, "bayerrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL"), options.prevdemo != PD_Sidecar) +const Glib::ustring BayerRAWExposure::TOOL_NAME = "bayerrawexposure"; + +BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOS_BLACKPOINT_LABEL"), options.prevdemo != PD_Sidecar) { PexBlack1 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_1"), -2048, 2048, 1.0, 0)); //black level PexBlack1->setAdjusterListener (this); diff --git a/rtgui/bayerrawexposure.h b/rtgui/bayerrawexposure.h index eb18aa0e3..53c5817f8 100644 --- a/rtgui/bayerrawexposure.h +++ b/rtgui/bayerrawexposure.h @@ -31,6 +31,8 @@ class BayerRAWExposure final : public FoldableToolPanel { public: + static const Glib::ustring TOOL_NAME; + BayerRAWExposure (); void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; diff --git a/rtgui/blackwhite.cc b/rtgui/blackwhite.cc index 97e54c778..2d3c35a54 100644 --- a/rtgui/blackwhite.cc +++ b/rtgui/blackwhite.cc @@ -34,8 +34,9 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring BlackWhite::TOOL_NAME = "blackwhite"; -BlackWhite::BlackWhite (): FoldableToolPanel(this, "blackwhite", M("TP_BWMIX_LABEL"), false, true) +BlackWhite::BlackWhite (): FoldableToolPanel(this, TOOL_NAME, M("TP_BWMIX_LABEL"), false, true) { CurveListener::setMulti(true); @@ -49,7 +50,8 @@ BlackWhite::BlackWhite (): FoldableToolPanel(this, "blackwhite", M("TP_BWMIX_LAB metHBox->set_spacing (2); Gtk::Label* metLabel = Gtk::manage (new Gtk::Label (M("TP_BWMIX_MET") + ":")); metHBox->pack_start (*metLabel, Gtk::PACK_SHRINK); - method = Gtk::manage (new MyComboBoxText ()); + + method = Gtk::manage (new MyComboBoxText ()); method->append (M("TP_BWMIX_MET_DESAT")); method->append (M("TP_BWMIX_MET_LUMEQUAL")); method->append (M("TP_BWMIX_MET_CHANMIX")); diff --git a/rtgui/blackwhite.h b/rtgui/blackwhite.h index 505d842db..fe41ccda0 100644 --- a/rtgui/blackwhite.h +++ b/rtgui/blackwhite.h @@ -40,6 +40,7 @@ class BlackWhite final : public ColorProvider { public: + static const Glib::ustring TOOL_NAME; BlackWhite (); ~BlackWhite () override; diff --git a/rtgui/cacorrection.cc b/rtgui/cacorrection.cc index 79df63963..b61c6e9e1 100644 --- a/rtgui/cacorrection.cc +++ b/rtgui/cacorrection.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -CACorrection::CACorrection () : FoldableToolPanel(this, "cacorrection", M("TP_CACORRECTION_LABEL")) +const Glib::ustring CACorrection::TOOL_NAME = "cacorrection"; + +CACorrection::CACorrection () : FoldableToolPanel(this, TOOL_NAME, M("TP_CACORRECTION_LABEL")) { Gtk::Image* icaredL = Gtk::manage (new RTImage ("circle-red-cyan-small")); diff --git a/rtgui/cacorrection.h b/rtgui/cacorrection.h index 12d6396eb..7afccb4de 100644 --- a/rtgui/cacorrection.h +++ b/rtgui/cacorrection.h @@ -34,6 +34,7 @@ protected: Adjuster* blue; public: + static const Glib::ustring TOOL_NAME; CACorrection (); diff --git a/rtgui/chmixer.cc b/rtgui/chmixer.cc index c64b7f252..7cd924dd5 100644 --- a/rtgui/chmixer.cc +++ b/rtgui/chmixer.cc @@ -25,7 +25,9 @@ using namespace rtengine; using namespace rtengine::procparams; -ChMixer::ChMixer (): FoldableToolPanel(this, "chmixer", M("TP_CHMIXER_LABEL"), false, true) +const Glib::ustring ChMixer::TOOL_NAME = "chmixer"; + +ChMixer::ChMixer (): FoldableToolPanel(this, TOOL_NAME, M("TP_CHMIXER_LABEL"), false, true) { imgIcon[0] = Gtk::manage (new RTImage ("circle-red-small")); diff --git a/rtgui/chmixer.h b/rtgui/chmixer.h index d80b89cf7..831449c30 100644 --- a/rtgui/chmixer.h +++ b/rtgui/chmixer.h @@ -36,6 +36,7 @@ protected: Gtk::Image *imgIcon[9]; public: + static const Glib::ustring TOOL_NAME; ChMixer (); diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index 803182774..dfdaf169e 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -44,6 +44,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring ColorAppearance::TOOL_NAME = "colorappearance"; + static double wbSlider2Temp (double sval) { @@ -212,7 +214,7 @@ static double wbTemp2Slider (double temp) } -ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance", M ("TP_COLORAPP_LABEL"), false, true) +ColorAppearance::ColorAppearance () : FoldableToolPanel (this, TOOL_NAME, M ("TP_COLORAPP_LABEL"), false, true) { CurveListener::setMulti (true); std::vector milestones; @@ -220,7 +222,6 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" milestones.push_back ( GradientMilestone (1., 1., 1., 1.) ); auto m = ProcEventMapper::getInstance(); - 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"); @@ -269,10 +270,6 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" catHBox->pack_start(*catmethod); genVBox->pack_start (*catHBox, Gtk::PACK_SHRINK); - presetcat02 = Gtk::manage (new Gtk::CheckButton (M ("TP_COLORAPP_PRESETCAT02"))); - presetcat02->set_tooltip_markup (M("TP_COLORAPP_PRESETCAT02_TOOLTIP")); - presetcat02conn = presetcat02->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::presetcat02pressed)); -// genVBox->pack_start (*presetcat02, Gtk::PACK_SHRINK); genFrame->add (*genVBox); pack_start (*genFrame, Gtk::PACK_EXPAND_WIDGET, 4); @@ -686,14 +683,22 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" 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")); - + tempout->throwOnButtonRelease(); + tempout->addAutoButton (M ("TP_COLORAPP_TEMPOUT_TOOLTIP")); + // I renable tempout with addautobutton to work properly (and all code disabled). There are certainly some redundancies, but it doesn't matter tempout->show(); greenout->show(); ybout->show(); - p3VBox->pack_start (*tempout); - p3VBox->pack_start (*greenout); + Gtk::Frame *tempgreenFrame; + tempgreenFrame = Gtk::manage(new Gtk::Frame()); + tempgreenFrame->set_label_align (0.025, 0.5); + Gtk::Box* tempgreenVBox; + tempgreenVBox = Gtk::manage ( new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + tempgreenVBox->set_spacing (2); + tempgreenVBox->pack_start (*tempout); + tempgreenVBox->pack_start (*greenout); + tempgreenFrame->add(*tempgreenVBox); + p3VBox->pack_start(*tempgreenFrame); p3VBox->pack_start (*ybout); Gtk::Box* surrHBox = Gtk::manage (new Gtk::Box ()); @@ -827,7 +832,7 @@ void ColorAppearance::neutral_pressed () qcontrast->resetValue (false); colorh->resetValue (false); tempout->resetValue (false); -// tempout->setAutoValue (true); + tempout->setAutoValue (true); greenout->resetValue (false); ybout->resetValue (false); tempsc->resetValue (false); @@ -874,7 +879,6 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) tcmodeconn.block (true); tcmode2conn.block (true); tcmode3conn.block (true); - presetcat02conn.block (true); shape->setCurve (pp->colorappearance.curve); shape2->setCurve (pp->colorappearance.curve2); shape3->setCurve (pp->colorappearance.curve3); @@ -882,7 +886,6 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) toneCurveMode2->set_active (toUnderlying(pp->colorappearance.curveMode2)); toneCurveMode3->set_active (toUnderlying(pp->colorappearance.curveMode3)); curveMode3Changed(); // This will set the correct sensitive state of depending Adjusters - presetcat02->set_active(pp->colorappearance.presetcat02); nexttemp = pp->wb.temperature; nextgreen = 1.; //pp->wb.green; @@ -920,7 +923,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) adapscen->setAutoInconsistent (multiImage && !pedited->colorappearance.autoadapscen); ybscen->setAutoInconsistent (multiImage && !pedited->colorappearance.autoybscen); set_inconsistent (multiImage && !pedited->colorappearance.enabled); - // tempout->setAutoInconsistent (multiImage && !pedited->colorappearance.autotempout); + tempout->setAutoInconsistent (multiImage && !pedited->colorappearance.autotempout); shape->setUnChanged (!pedited->colorappearance.curve); shape2->setUnChanged (!pedited->colorappearance.curve2); @@ -946,7 +949,6 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) if (!pedited->colorappearance.curveMode3) { toneCurveMode3->set_active (3); } - presetcat02->set_inconsistent(!pedited->colorappearance.presetcat02); } @@ -1106,7 +1108,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) lastAutoAdapscen = pp->colorappearance.autoadapscen; lastAutoDegreeout = pp->colorappearance.autodegreeout; lastAutoybscen = pp->colorappearance.autoybscen; -// lastAutotempout = pp->colorappearance.autotempout; + lastAutotempout = pp->colorappearance.autotempout; degree->setValue (pp->colorappearance.degree); degree->setAutoValue (pp->colorappearance.autodegree); @@ -1129,15 +1131,11 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) qcontrast->setValue (pp->colorappearance.qcontrast); colorh->setValue (pp->colorappearance.colorh); tempout->setValue (pp->colorappearance.tempout); -// tempout->setAutoValue (pp->colorappearance.autotempout); + tempout->setAutoValue (pp->colorappearance.autotempout); greenout->setValue (pp->colorappearance.greenout); ybout->setValue (pp->colorappearance.ybout); tempsc->setValue (pp->colorappearance.tempsc); greensc->setValue (pp->colorappearance.greensc); - presetcat02conn.block (true); - presetcat02->set_active (pp->colorappearance.presetcat02); - presetcat02conn.block (false); - lastpresetcat02 = pp->colorappearance.presetcat02; if (complexmethod->get_active_row_number() == 0) { updateGUIToMode(0); @@ -1197,12 +1195,11 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) pp->colorappearance.curve2 = shape2->getCurve (); pp->colorappearance.curve3 = shape3->getCurve (); pp->colorappearance.tempout = tempout->getValue (); -// pp->colorappearance.autotempout = tempout->getAutoValue (); + pp->colorappearance.autotempout = tempout->getAutoValue (); pp->colorappearance.greenout = greenout->getValue (); pp->colorappearance.ybout = ybout->getValue (); pp->colorappearance.tempsc = tempsc->getValue (); pp->colorappearance.greensc = greensc->getValue (); - pp->colorappearance.presetcat02 = presetcat02->get_active(); int tcMode = toneCurveMode->get_active_row_number(); @@ -1276,8 +1273,7 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) pedited->colorappearance.ybout = ybout->getEditedState (); pedited->colorappearance.tempsc = tempsc->getEditedState (); pedited->colorappearance.greensc = greensc->getEditedState (); - pedited->colorappearance.presetcat02 = presetcat02->get_inconsistent (); -// pedited->colorappearance.autotempout = !tempout->getAutoInconsistent(); + pedited->colorappearance.autotempout = !tempout->getAutoInconsistent(); } @@ -1369,7 +1365,9 @@ void ColorAppearance::updateGUIToMode(int mode) curveEditorG->hide(); curveEditorG2->hide(); curveEditorG3->hide(); - greenout->hide(); + //greenout->hide(); + greenout->set_sensitive(false); + badpixsl->hide(); datacie->hide(); } else { @@ -1378,7 +1376,8 @@ void ColorAppearance::updateGUIToMode(int mode) curveEditorG->show(); curveEditorG2->show(); curveEditorG3->show(); - greenout->show(); + // greenout->show(); + greenout->set_sensitive(true); badpixsl->show(); datacie->show(); } @@ -1397,10 +1396,6 @@ void ColorAppearance::convertParamToNormal() shape2->reset(); shape3->reset(); wbmodel->set_active (0); - if (presetcat02->get_active ()) { - wbmodel->set_active (2); - illumChanged(); - } if (catmethod->get_active_row_number() == 1 || catmethod->get_active_row_number() == 2) { wbmodel->set_active (2); illumChanged(); @@ -1488,13 +1483,13 @@ void ColorAppearance::catmethodChanged() ybout->setValue(18); tempout->setValue (nexttemp); -/* if(tempout->getAutoValue()) { - tempout->resetValue (false); - } else { - tempout->setValue (nexttemp); - tempout->setAutoValue (true); - } -*/ + if(tempout->getAutoValue()) { + tempout->resetValue (false); + } else { + tempout->setValue (nexttemp); + tempout->setAutoValue (true); + } + greenout->setValue (nextgreen); enableListener(); @@ -1543,7 +1538,7 @@ void ColorAppearance::catmethodChanged() adaplum->resetValue (false); degreeout->resetValue (false); ybout->resetValue (false); - // tempout->resetValue (false); + tempout->resetValue (false); tempout->setValue (nexttemp); greenout->resetValue (false); enableListener(); @@ -1705,140 +1700,6 @@ void ColorAppearance::badpix_toggled () { } */ -void ColorAppearance::presetcat02pressed () //keep in case of... -{ - if (presetcat02->get_active ()) { - disableListener(); - jlight->resetValue (false); - qbright->resetValue (false); - chroma->resetValue (false); - schroma->resetValue (false); - mchroma->resetValue (false); - rstprotection->resetValue (false); - contrast->resetValue (false); - qcontrast->resetValue (false); - colorh->resetValue (false); - tempout->resetValue (false); - greenout->resetValue (false); - ybout->resetValue (false); - tempsc->resetValue (false); - greensc->resetValue (false); - badpixsl->resetValue (false); - wbmodel->set_active (0); - illum->set_active (2); - toneCurveMode->set_active (0); - toneCurveMode2->set_active (1); - toneCurveMode3->set_active (0); - shape->reset(); - shape2->reset(); - shape3->reset(); - gamutconn.block (true); - gamut->set_active (true); - gamutconn.block (false); - degree->setAutoValue (true); - degree->resetValue (false); - degree->setValue(90); - adapscen->resetValue (false); - adapscen->setAutoValue (true); - degreeout->resetValue (false); - degreeout->setAutoValue (true); - ybscen->resetValue (false); - ybscen->setAutoValue (true); - surrsrc->set_active (0); - wbmodel->set_active (2); - tempsc->resetValue (false); - greensc->resetValue (false); - adapscen->setValue(400.); - ybscen->setValue(18); - surround->set_active (0); - adaplum->setValue(400.); - degreeout->setValue(90); - ybout->setValue(18); - tempout->setValue (nexttemp); - -/* if(tempout->getAutoValue()) { - tempout->resetValue (false); - } else { - tempout->setValue (nexttemp); - tempout->setAutoValue (true); - } -*/ - greenout->setValue (nextgreen); - enableListener(); - } else { - disableListener(); -/* jlight->resetValue (false); - qbright->resetValue (false); - chroma->resetValue (false); - schroma->resetValue (false); - mchroma->resetValue (false); - rstprotection->resetValue (false); - contrast->resetValue (false); - qcontrast->resetValue (false); - colorh->resetValue (false); - tempout->resetValue (false); - greenout->resetValue (false); - ybout->resetValue (false); - tempsc->resetValue (false); - greensc->resetValue (false); - badpixsl->resetValue (false); - wbmodel->set_active (0); - toneCurveMode->set_active (0); - toneCurveMode2->set_active (0); - toneCurveMode3->set_active (0); - shape->reset(); - shape2->reset(); - shape3->reset(); - gamutconn.block (true); - gamut->set_active (true); - gamutconn.block (false); -*/ - degree->setAutoValue (true); - degree->resetValue (false); - adapscen->resetValue (false); - adapscen->setAutoValue (true); - degreeout->resetValue (false); - degreeout->setAutoValue (true); - ybscen->resetValue (false); - ybscen->setAutoValue (true); - surrsrc->set_active (0); - wbmodel->set_active (0); - illum->set_active (2); - tempsc->resetValue (false); - greensc->resetValue (false); - adapscen->resetValue (false); - ybscen->resetValue (false); - surround->set_active (0); - adaplum->resetValue (false); - degreeout->resetValue (false); - ybout->resetValue (false); - tempout->resetValue (false); - greenout->resetValue (false); - enableListener(); - - } - if (batchMode) { - if (presetcat02->get_inconsistent()) { - presetcat02->set_inconsistent (false); - presetcat02conn.block (true); - presetcat02->set_active (false); - presetcat02conn.block (false); - } else if (lastpresetcat02) { - presetcat02->set_inconsistent (true); - } - - lastpresetcat02 = presetcat02->get_active (); - } - - if (listener) { - if (presetcat02->get_active ()) { - listener->panelChanged (Evcatpreset, M ("GENERAL_ENABLED")); - } else { - listener->panelChanged (Evcatpreset, M ("GENERAL_DISABLED")); - } - } - -} void ColorAppearance::datacie_toggled () { @@ -2001,9 +1862,6 @@ void ColorAppearance::autoCamChanged (double ccam, double ccamout) void ColorAppearance::adapCamChanged (double cadap) { - if(presetcat02->get_active()){ - return; - } idle_register.add( [this, cadap]() -> bool @@ -2018,14 +1876,14 @@ void ColorAppearance::adapCamChanged (double cadap) void ColorAppearance::wbCamChanged (double temp, double tin) -{ +{//reactivate this function idle_register.add( [this, temp, tin]() -> bool { disableListener(); tempout->setValue(temp); - greenout->setValue(tin); + greenout->setValue(tin); enableListener(); return false; } @@ -2034,9 +1892,6 @@ void ColorAppearance::wbCamChanged (double temp, double tin) void ColorAppearance::ybCamChanged (int ybsc) { - if(presetcat02->get_active()){ - return; - } idle_register.add( [this, ybsc]() -> bool @@ -2122,16 +1977,6 @@ void ColorAppearance::adjusterChanged(Adjuster* a, double newval) void ColorAppearance::adjusterAutoToggled(Adjuster* a) { - /* - if(presetcat02->get_active ()){ - if(tempout->getAutoValue()) { - tempout->resetValue (false); - } else { - tempout->setValue (nexttemp); - tempout->setAutoValue (true); - } - } -*/ if (multiImage) { if (degree->getAutoInconsistent()) { degree->setAutoInconsistent (false); @@ -2167,7 +2012,7 @@ void ColorAppearance::adjusterAutoToggled(Adjuster* a) ybscen->setAutoInconsistent (true); } -/* lastAutotempout = tempout->getAutoValue(); + lastAutotempout = tempout->getAutoValue(); if (tempout->getAutoInconsistent()) { tempout->setAutoInconsistent (false); @@ -2177,7 +2022,7 @@ void ColorAppearance::adjusterAutoToggled(Adjuster* a) } lastAutotempout = tempout->getAutoValue(); -*/ + } if (listener && (multiImage || getEnabled()) ) { @@ -2221,7 +2066,7 @@ void ColorAppearance::adjusterAutoToggled(Adjuster* a) listener->panelChanged (EvCATAutoyb, M ("GENERAL_DISABLED")); } } -/* + if (a == tempout) { if (tempout->getAutoInconsistent()) { listener->panelChanged (EvCATAutotempout, M ("GENERAL_UNCHANGED")); @@ -2231,7 +2076,7 @@ void ColorAppearance::adjusterAutoToggled(Adjuster* a) listener->panelChanged (EvCATAutotempout, M ("GENERAL_DISABLED")); } } -*/ + } } void ColorAppearance::enabledChanged () diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index ce1971e85..dcf19b977 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -39,6 +39,8 @@ class ColorAppearance final : public ColorProvider { public: + static const Glib::ustring TOOL_NAME; + ColorAppearance (); ~ColorAppearance () override; @@ -68,7 +70,6 @@ public: bool adapCamComputed_ (); void ybCamChanged (int yb) override; bool ybCamComputed_ (); - void presetcat02pressed (); void curveChanged (CurveEditor* ce) override; void curveMode1Changed (); bool curveMode1Changed_ (); @@ -106,7 +107,6 @@ public: void writeOptions (std::vector &tpOpen); private: - rtengine::ProcEvent Evcatpreset; rtengine::ProcEvent EvCATAutotempout; rtengine::ProcEvent EvCATillum; rtengine::ProcEvent EvCATcomplex; @@ -159,8 +159,6 @@ private: Gtk::CheckButton* tonecie; // Gtk::CheckButton* sharpcie; Gtk::Button* neutral; - Gtk::CheckButton* presetcat02; - sigc::connection presetcat02conn; MyComboBoxText* surrsrc; sigc::connection surrsrcconn; @@ -198,7 +196,6 @@ private: bool lastgamut; bool lastdatacie; bool lasttonecie; - bool lastpresetcat02; double nexttemp; double nextgreen; diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index 0649a3c8c..3ad1b01e4 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -14,6 +14,7 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring ColorToning::TOOL_NAME = "colortoning"; namespace { @@ -33,7 +34,7 @@ inline float round_ab(float v) } // namespace -ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLORTONING_LABEL"), false, true) +ColorToning::ColorToning () : FoldableToolPanel(this, TOOL_NAME, M("TP_COLORTONING_LABEL"), false, true) { nextbw = 0; CurveListener::setMulti(true); diff --git a/rtgui/colortoning.h b/rtgui/colortoning.h index be3a83c2d..e763a069c 100644 --- a/rtgui/colortoning.h +++ b/rtgui/colortoning.h @@ -30,6 +30,8 @@ class ColorToning final : public AdjusterListener { public: + static const Glib::ustring TOOL_NAME; + ColorToning (); ~ColorToning() override; void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc index 9f380d080..37efe3fee 100644 --- a/rtgui/controlspotpanel.cc +++ b/rtgui/controlspotpanel.cc @@ -24,6 +24,7 @@ #include "options.h" #include "../rtengine/procparams.h" #include "rtimage.h" +#include "eventmapper.h" using namespace rtengine; using namespace procparams; @@ -55,6 +56,7 @@ ControlSpotPanel::ControlSpotPanel(): qualityMethod_(Gtk::manage(new MyComboBoxText())), //complexMethod_(Gtk::manage(new MyComboBoxText())), wavMethod_(Gtk::manage(new MyComboBoxText())), + avoidgamutMethod_(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))), @@ -76,15 +78,13 @@ ControlSpotPanel::ControlSpotPanel(): balanh_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BALANH"), 0.2, 2.5, 0.1, 1.0, Gtk::manage(new RTImage("rawtherapee")), Gtk::manage(new RTImage("circle-red-green-small"))))), colorde_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_COLORDE"), -15, 15, 2, 5, Gtk::manage(new RTImage("circle-blue-yellow-small")), Gtk::manage(new RTImage("circle-gray-green-small"))))), colorscope_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_COLORSCOPE"), 0., 100.0, 1., 30.))), - avoidrad_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_AVOIDRAD"), 0., 30.0, 0.1, 0.7))), + avoidrad_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_AVOIDRAD"), 0., 30.0, 0.1, 0.))), scopemask_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SCOPEMASK"), 0, 100, 1, 60))), denoichmask_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DENOIMASK"), 0., 100., 0.5, 0))), lumask_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LUMASK"), -50, 30, 1, 10, Gtk::manage(new RTImage("circle-yellow-small")), Gtk::manage(new RTImage("circle-gray-small")) ))), 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")))), - avoidmun_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_AVOIDMUN")))), 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")))), @@ -100,6 +100,7 @@ ControlSpotPanel::ControlSpotPanel(): preview_(Gtk::manage(new Gtk::ToggleButton(M("TP_LOCALLAB_PREVIEW")))), ctboxshape(Gtk::manage(new Gtk::Box())), ctboxshapemethod(Gtk::manage(new Gtk::Box())), + ctboxgamut(Gtk::manage(new Gtk::Box())), controlPanelListener(nullptr), lastObject_(-1), @@ -111,6 +112,8 @@ ControlSpotPanel::ControlSpotPanel(): excluFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_EXCLUF")))), maskPrevActive(false) { + auto m = ProcEventMapper::getInstance(); + EvLocallabavoidgamutMethod = m->newEvent(AUTOEXP, "HISTORY_MSG_LOCAL_GAMUTMUNSEL"); const bool showtooltip = options.showtooltip; pack_start(*hishow_); @@ -397,23 +400,30 @@ ControlSpotPanel::ControlSpotPanel(): activConn_ = activ_->signal_toggled().connect( sigc::mem_fun(*this, &ControlSpotPanel::activChanged)); - avoidConn_ = avoid_->signal_toggled().connect( - sigc::mem_fun(*this, &ControlSpotPanel::avoidChanged)); - avoidmunConn_ = avoidmun_->signal_toggled().connect( - sigc::mem_fun(*this, &ControlSpotPanel::avoidmunChanged)); + Gtk::Label* const labelgamut = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_AVOID") + ":")); + ctboxgamut->pack_start(*labelgamut, Gtk::PACK_SHRINK, 4); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTNON")); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTLABRELA")); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTXYZABSO")); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTXYZRELA")); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTMUNSELL")); + avoidgamutMethod_->set_active(4); + avoidgamutconn_ = avoidgamutMethod_->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::avoidgamutMethodChanged)); + ctboxgamut->pack_start(*avoidgamutMethod_); + if (showtooltip) { + ctboxgamut->set_tooltip_text(M("TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP")); + } - Gtk::Frame* const avFrame = Gtk::manage(new Gtk::Frame()); + Gtk::Frame* const avFrame = Gtk::manage(new Gtk::Frame()); ToolParamBlock* const avbox = Gtk::manage(new ToolParamBlock()); avFrame->set_label_align(0.025, 0.5); - avFrame->set_label_widget(*avoid_); + avbox->pack_start(*ctboxgamut); avbox->pack_start(*avoidrad_); - avbox->pack_start(*avoidmun_); avFrame->add(*avbox); specCaseBox->pack_start(*avFrame); - if (showtooltip) { - avoidmun_->set_tooltip_text(M("TP_LOCALLAB_AVOIDMUN_TOOLTIP")); - } blwhConn_ = blwh_->signal_toggled().connect( sigc::mem_fun(*this, &ControlSpotPanel::blwhChanged)); @@ -429,7 +439,6 @@ ControlSpotPanel::ControlSpotPanel(): if (showtooltip) { recurs_->set_tooltip_text(M("TP_LOCALLAB_RECURS_TOOLTIP")); - avoid_->set_tooltip_text(M("TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP")); } specCaseBox->pack_start(*recurs_); @@ -854,8 +863,6 @@ void ControlSpotPanel::load_ControlSpot_param() avoidrad_->setValue((double)row[spots_.avoidrad]); hishow_->set_active(row[spots_.hishow]); activ_->set_active(row[spots_.activ]); - avoid_->set_active(row[spots_.avoid]); - avoidmun_->set_active(row[spots_.avoidmun]); blwh_->set_active(row[spots_.blwh]); recurs_->set_active(row[spots_.recurs]); // laplac_->set_active(row[spots_.laplac]); @@ -868,6 +875,8 @@ void ControlSpotPanel::load_ControlSpot_param() //savrest_->set_active(row[spots_.savrest]); //complexMethod_->set_active(row[spots_.complexMethod]); wavMethod_->set_active(row[spots_.wavMethod]); + avoidgamutMethod_->set_active(row[spots_.avoidgamutMethod]); + } void ControlSpotPanel::controlspotChanged() @@ -1055,6 +1064,34 @@ void ControlSpotPanel::spotMethodChanged() } } +void ControlSpotPanel::avoidgamutMethodChanged() +{ + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + const int meth = avoidgamutMethod_->get_active_row_number(); + avoidrad_->show(); + + if(meth == 2 || meth == 3 || meth == 4) { + avoidrad_->hide(); + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + row[spots_.avoidgamutMethod] = avoidgamutMethod_->get_active_row_number(); + + // Raise event + if (listener) { + listener->panelChanged(EvLocallabavoidgamutMethod, avoidgamutMethod_->get_active_text()); + } + +} + void ControlSpotPanel::shapeMethodChanged() { // printf("shapeMethodChanged\n"); @@ -1217,6 +1254,7 @@ void ControlSpotPanel::updateParamVisibility() // Update Control Spot GUI according to shapeMethod_ combobox state (to be compliant with shapeMethodChanged function) const int method = shapeMethod_->get_active_row_number(); + const int meth = avoidgamutMethod_->get_active_row_number(); if (!batchMode) { if (method == 1 || method == 3) { // Symmetrical cases @@ -1260,6 +1298,12 @@ void ControlSpotPanel::updateParamVisibility() centerY_->show(); } + if(meth == 1) { + avoidrad_->show(); + } else { + avoidrad_->hide(); +} + // 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(); @@ -1588,57 +1632,6 @@ void ControlSpotPanel::hishowChanged() } - -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::avoidmunChanged() -{ - // printf("avoidmunChanged\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_.avoidmun] = avoidmun_->get_active(); - - // Raise event - if (listener) { - if (avoidmun_->get_active()) { - listener->panelChanged(EvLocallabSpotavoidmun, M("GENERAL_ENABLED")); - } else { - listener->panelChanged(EvLocallabSpotavoidmun, M("GENERAL_DISABLED")); - } - } -} - void ControlSpotPanel::activChanged() { // printf("activChanged\n"); @@ -1859,8 +1852,6 @@ void ControlSpotPanel::disableParamlistener(bool cond) avoidrad_->block(cond); hishowconn_.block(cond); activConn_.block(cond); - avoidConn_.block(cond); - avoidmunConn_.block(cond); blwhConn_.block(cond); recursConn_.block(cond); laplacConn_.block(cond); @@ -1872,6 +1863,8 @@ void ControlSpotPanel::disableParamlistener(bool cond) //savrestConn_.block(cond); //complexMethodconn_.block(cond); wavMethodconn_.block(cond); + avoidgamutconn_.block(cond); + } void ControlSpotPanel::setParamEditable(bool cond) @@ -1906,8 +1899,6 @@ void ControlSpotPanel::setParamEditable(bool cond) avoidrad_->set_sensitive(cond); hishow_->set_sensitive(cond); activ_->set_sensitive(cond); - avoid_->set_sensitive(cond); - avoidmun_->set_sensitive(cond); blwh_->set_sensitive(cond); recurs_->set_sensitive(cond); laplac_->set_sensitive(cond); @@ -1920,6 +1911,7 @@ void ControlSpotPanel::setParamEditable(bool cond) //complexMethod_->set_sensitive(cond); wavMethod_->set_sensitive(cond); preview_->set_sensitive(cond); + avoidgamutMethod_->set_sensitive(cond); if (!cond) { // Reset complex parameters visibility to default state @@ -2592,8 +2584,6 @@ ControlSpotPanel::SpotRow* ControlSpotPanel::getSpot(const int index) r->lumask = row[spots_.lumask]; r->hishow = row[spots_.hishow]; r->activ = row[spots_.activ]; - r->avoid = row[spots_.avoid]; - r->avoidmun = row[spots_.avoidmun]; r->blwh = row[spots_.blwh]; r->recurs = row[spots_.recurs]; r->laplac = row[spots_.laplac]; @@ -2601,6 +2591,7 @@ ControlSpotPanel::SpotRow* ControlSpotPanel::getSpot(const int index) r->shortc = row[spots_.shortc]; //r->savrest = row[spots_.savrest]; r->wavMethod = row[spots_.wavMethod]; + r->avoidgamutMethod = row[spots_.avoidgamutMethod]; return r; } @@ -2725,8 +2716,6 @@ void ControlSpotPanel::addControlSpot(SpotRow* newSpot) row[spots_.avoidrad] = newSpot->avoidrad; row[spots_.hishow] = newSpot->hishow; row[spots_.activ] = newSpot->activ; - row[spots_.avoid] = newSpot->avoid; - row[spots_.avoidmun] = newSpot->avoidmun; row[spots_.blwh] = newSpot->blwh; row[spots_.recurs] = newSpot->recurs; row[spots_.laplac] = newSpot->laplac; @@ -2738,6 +2727,7 @@ void ControlSpotPanel::addControlSpot(SpotRow* newSpot) //row[spots_.savrest] = newSpot->savrest; row[spots_.complexMethod] = newSpot->complexMethod; row[spots_.wavMethod] = newSpot->wavMethod; + row[spots_.avoidgamutMethod] = newSpot->avoidgamutMethod; updateParamVisibility(); disableParamlistener(false); @@ -2845,8 +2835,6 @@ ControlSpotPanel::ControlSpots::ControlSpots() add(avoidrad); add(hishow); add(activ); - add(avoid); - add(avoidmun); add(blwh); add(recurs); add(laplac); @@ -2858,6 +2846,7 @@ ControlSpotPanel::ControlSpots::ControlSpots() //add(savrest); add(complexMethod); add(wavMethod); + add(avoidgamutMethod); } //----------------------------------------------------------------------------- diff --git a/rtgui/controlspotpanel.h b/rtgui/controlspotpanel.h index 92406c690..b1e191b0e 100644 --- a/rtgui/controlspotpanel.h +++ b/rtgui/controlspotpanel.h @@ -57,6 +57,7 @@ public: int sensiexclu; int structexclu; int shapeMethod; // 0 = Independent (mouse), 1 = Symmetrical (mouse), 2 = Independent (mouse + sliders), 3 = Symmetrical (mouse + sliders) + int avoidgamutMethod; int locX; int locXL; int locY; @@ -79,8 +80,6 @@ public: double avoidrad; bool hishow; bool activ; - bool avoid; - bool avoidmun; bool blwh; bool recurs; bool laplac; @@ -243,7 +242,8 @@ private: void spotMethodChanged(); void shapeMethodChanged(); void qualityMethodChanged(); - //void complexMethodChanged(); + void avoidgamutMethodChanged(); + //void complexMethodChanged(); void wavMethodChanged(); void updateParamVisibility(); @@ -252,8 +252,6 @@ private: void hishowChanged(); void activChanged(); - void avoidChanged(); - void avoidmunChanged(); void blwhChanged(); void recursChanged(); void laplacChanged(); @@ -293,6 +291,7 @@ private: 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 avoidgamutMethod; Gtk::TreeModelColumn locX; Gtk::TreeModelColumn locXL; Gtk::TreeModelColumn locY; @@ -315,8 +314,6 @@ private: Gtk::TreeModelColumn avoidrad; Gtk::TreeModelColumn hishow; Gtk::TreeModelColumn activ; - Gtk::TreeModelColumn avoid; - Gtk::TreeModelColumn avoidmun; Gtk::TreeModelColumn blwh; Gtk::TreeModelColumn recurs; Gtk::TreeModelColumn laplac; @@ -347,6 +344,7 @@ private: }; ControlSpots spots_; + rtengine::ProcEvent EvLocallabavoidgamutMethod; // Child widgets Gtk::ScrolledWindow* const scrolledwindow_; @@ -381,6 +379,8 @@ private: //sigc::connection complexMethodconn_; MyComboBoxText* const wavMethod_; sigc::connection wavMethodconn_; + MyComboBoxText* const avoidgamutMethod_; + sigc::connection avoidgamutconn_; Adjuster* const sensiexclu_; Adjuster* const structexclu_; @@ -411,10 +411,6 @@ private: sigc::connection hishowconn_; Gtk::CheckButton* const activ_; sigc::connection activConn_; - Gtk::CheckButton* const avoid_; - sigc::connection avoidConn_; - Gtk::CheckButton* const avoidmun_; - sigc::connection avoidmunConn_; Gtk::CheckButton* const blwh_; sigc::connection blwhConn_; Gtk::CheckButton* const recurs_; @@ -438,6 +434,7 @@ private: Gtk::Box* const ctboxshape; Gtk::Box* const ctboxshapemethod; + Gtk::Box* const ctboxgamut; // Internal variables ControlPanelListener* controlPanelListener; diff --git a/rtgui/crop.cc b/rtgui/crop.cc index bf26dcc63..0bbbdbf1f 100644 --- a/rtgui/crop.cc +++ b/rtgui/crop.cc @@ -29,6 +29,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring Crop::TOOL_NAME = "crop"; + namespace { @@ -124,7 +126,7 @@ private: }; Crop::Crop(): - FoldableToolPanel(this, "crop", M("TP_CROP_LABEL"), false, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_CROP_LABEL"), false, true), crop_ratios(new CropRatios), opt(0), wDirty(true), diff --git a/rtgui/crop.h b/rtgui/crop.h index c6636b917..83eb6bbbb 100644 --- a/rtgui/crop.h +++ b/rtgui/crop.h @@ -41,6 +41,8 @@ class Crop final : public rtengine::SizeListener { public: + static const Glib::ustring TOOL_NAME; + Crop(); ~Crop() override; diff --git a/rtgui/darkframe.cc b/rtgui/darkframe.cc index 84b624cf2..648f96718 100644 --- a/rtgui/darkframe.cc +++ b/rtgui/darkframe.cc @@ -30,7 +30,9 @@ using namespace rtengine; using namespace rtengine::procparams; -DarkFrame::DarkFrame () : FoldableToolPanel(this, "darkframe", M("TP_DARKFRAME_LABEL")), dfChanged(false), lastDFauto(false), dfp(nullptr), israw(true) +const Glib::ustring DarkFrame::TOOL_NAME = "darkframe"; + +DarkFrame::DarkFrame () : FoldableToolPanel(this, TOOL_NAME, M("TP_DARKFRAME_LABEL")), dfChanged(false), lastDFauto(false), dfp(nullptr), israw(true) { hbdf = Gtk::manage(new Gtk::Box()); hbdf->set_spacing(4); diff --git a/rtgui/darkframe.h b/rtgui/darkframe.h index cbd7816d6..086ee7ec5 100644 --- a/rtgui/darkframe.h +++ b/rtgui/darkframe.h @@ -62,6 +62,7 @@ protected: bool israw; public: + static const Glib::ustring TOOL_NAME; DarkFrame (); diff --git a/rtgui/defringe.cc b/rtgui/defringe.cc index 7aae8377a..72388ac8c 100644 --- a/rtgui/defringe.cc +++ b/rtgui/defringe.cc @@ -30,7 +30,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Defringe::Defringe () : FoldableToolPanel(this, "defringe", M("TP_DEFRINGE_LABEL"), true, true) +const Glib::ustring Defringe::TOOL_NAME = "defringe"; + +Defringe::Defringe () : FoldableToolPanel(this, TOOL_NAME, M("TP_DEFRINGE_LABEL"), true, true) { std::vector bottomMilestones; diff --git a/rtgui/defringe.h b/rtgui/defringe.h index ebf1eecd8..d939ff926 100644 --- a/rtgui/defringe.h +++ b/rtgui/defringe.h @@ -46,6 +46,7 @@ protected: bool edges; public: + static const Glib::ustring TOOL_NAME; Defringe (); ~Defringe () override; diff --git a/rtgui/dehaze.cc b/rtgui/dehaze.cc index 76d309afc..b77b76945 100644 --- a/rtgui/dehaze.cc +++ b/rtgui/dehaze.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Dehaze::Dehaze(): FoldableToolPanel(this, "dehaze", M("TP_DEHAZE_LABEL"), false, true) +const Glib::ustring Dehaze::TOOL_NAME = "dehaze"; + +Dehaze::Dehaze(): FoldableToolPanel(this, TOOL_NAME, M("TP_DEHAZE_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); EvDehazeEnabled = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_ENABLED"); diff --git a/rtgui/dehaze.h b/rtgui/dehaze.h index 155efa522..1da50d7dd 100644 --- a/rtgui/dehaze.h +++ b/rtgui/dehaze.h @@ -39,6 +39,7 @@ private: rtengine::ProcEvent EvDehazeSaturation; public: + static const Glib::ustring TOOL_NAME; Dehaze(); diff --git a/rtgui/dirpyrdenoise.cc b/rtgui/dirpyrdenoise.cc index 3bf7c21f4..f2b780eba 100644 --- a/rtgui/dirpyrdenoise.cc +++ b/rtgui/dirpyrdenoise.cc @@ -33,7 +33,9 @@ using namespace rtengine; using namespace rtengine::procparams; -DirPyrDenoise::DirPyrDenoise () : FoldableToolPanel(this, "dirpyrdenoise", M("TP_DIRPYRDENOISE_LABEL"), true, true), lastmedian(false) +const Glib::ustring DirPyrDenoise::TOOL_NAME = "dirpyrdenoise"; + +DirPyrDenoise::DirPyrDenoise () : FoldableToolPanel(this, TOOL_NAME, M("TP_DIRPYRDENOISE_LABEL"), true, true), lastmedian(false) { std::vector milestones; CurveListener::setMulti(true); diff --git a/rtgui/dirpyrdenoise.h b/rtgui/dirpyrdenoise.h index 71c9b1894..dadd96988 100644 --- a/rtgui/dirpyrdenoise.h +++ b/rtgui/dirpyrdenoise.h @@ -40,6 +40,8 @@ class DirPyrDenoise final : public ColorProvider { public: + static const Glib::ustring TOOL_NAME; + DirPyrDenoise (); ~DirPyrDenoise () override; diff --git a/rtgui/dirpyrequalizer.cc b/rtgui/dirpyrequalizer.cc index 9393d7c42..46966ea45 100644 --- a/rtgui/dirpyrequalizer.cc +++ b/rtgui/dirpyrequalizer.cc @@ -24,7 +24,9 @@ using namespace rtengine; using namespace rtengine::procparams; -DirPyrEqualizer::DirPyrEqualizer () : FoldableToolPanel(this, "dirpyrequalizer", M("TP_DIRPYREQUALIZER_LABEL"), true, true) +const Glib::ustring DirPyrEqualizer::TOOL_NAME = "dirpyrequalizer"; + +DirPyrEqualizer::DirPyrEqualizer () : FoldableToolPanel(this, TOOL_NAME, M("TP_DIRPYREQUALIZER_LABEL"), true, true) { std::vector milestones; diff --git a/rtgui/dirpyrequalizer.h b/rtgui/dirpyrequalizer.h index bb03e1a53..39b201b9b 100644 --- a/rtgui/dirpyrequalizer.h +++ b/rtgui/dirpyrequalizer.h @@ -56,6 +56,7 @@ protected: bool lastgamutlab; public: + static const Glib::ustring TOOL_NAME; DirPyrEqualizer (); ~DirPyrEqualizer () override; diff --git a/rtgui/distortion.cc b/rtgui/distortion.cc index aa81b568e..083c2f03a 100644 --- a/rtgui/distortion.cc +++ b/rtgui/distortion.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Distortion::Distortion (): FoldableToolPanel(this, "distortion", M("TP_DISTORTION_LABEL")) +const Glib::ustring Distortion::TOOL_NAME = "distortion"; + +Distortion::Distortion (): FoldableToolPanel(this, TOOL_NAME, M("TP_DISTORTION_LABEL")) { rlistener = nullptr; diff --git a/rtgui/distortion.h b/rtgui/distortion.h index 7ef33d73a..98044bacf 100644 --- a/rtgui/distortion.h +++ b/rtgui/distortion.h @@ -37,6 +37,7 @@ protected: LensGeomListener * rlistener; public: + static const Glib::ustring TOOL_NAME; Distortion (); diff --git a/rtgui/dynamicprofilepanel.cc b/rtgui/dynamicprofilepanel.cc index 865603b3a..feb6aea70 100644 --- a/rtgui/dynamicprofilepanel.cc +++ b/rtgui/dynamicprofilepanel.cc @@ -42,6 +42,7 @@ DynamicProfilePanel::EditDialog::EditDialog (const Glib::ustring &title, Gtk::Wi add_optional (M ("EXIFFILTER_CAMERA"), has_camera_, camera_); add_optional (M ("EXIFFILTER_LENS"), has_lens_, lens_); + add_optional (M ("EXIFFILTER_PATH"), has_path_, path_); imagetype_ = Gtk::manage (new MyComboBoxText()); imagetype_->append(Glib::ustring("(") + M("DYNPROFILEEDITOR_IMGTYPE_ANY") + ")"); @@ -93,6 +94,9 @@ void DynamicProfilePanel::EditDialog::set_rule ( has_lens_->set_active (rule.lens.enabled); lens_->set_text (rule.lens.value); + has_path_->set_active (rule.path.enabled); + path_->set_text (rule.path.value); + if (!rule.imagetype.enabled) { imagetype_->set_active(0); } else if (rule.imagetype.value == "STD") { @@ -136,6 +140,9 @@ DynamicProfileRule DynamicProfilePanel::EditDialog::get_rule() ret.lens.enabled = has_lens_->get_active(); ret.lens.value = lens_->get_text(); + ret.path.enabled = has_path_->get_active(); + ret.path.value = path_->get_text(); + ret.imagetype.enabled = imagetype_->get_active_row_number() > 0; switch (imagetype_->get_active_row_number()) { case 1: @@ -296,6 +303,16 @@ DynamicProfilePanel::DynamicProfilePanel(): *this, &DynamicProfilePanel::render_lens)); } + cell = Gtk::manage (new Gtk::CellRendererText()); + cols_count = treeview_.append_column (M ("EXIFFILTER_PATH"), *cell); + col = treeview_.get_column (cols_count - 1); + + if (col) { + col->set_cell_data_func ( + *cell, sigc::mem_fun ( + *this, &DynamicProfilePanel::render_path)); + } + cell = Gtk::manage (new Gtk::CellRendererText()); cols_count = treeview_.append_column (M ("EXIFFILTER_IMAGETYPE"), *cell); col = treeview_.get_column (cols_count - 1); @@ -375,6 +392,7 @@ void DynamicProfilePanel::update_rule (Gtk::TreeModel::Row row, row[columns_.expcomp] = rule.expcomp; row[columns_.camera] = rule.camera; row[columns_.lens] = rule.lens; + row[columns_.path] = rule.path; row[columns_.imagetype] = rule.imagetype; row[columns_.profilepath] = rule.profilepath; } @@ -398,6 +416,7 @@ DynamicProfileRule DynamicProfilePanel::to_rule (Gtk::TreeModel::Row row, ret.expcomp = row[columns_.expcomp]; ret.camera = row[columns_.camera]; ret.lens = row[columns_.lens]; + ret.path = row[columns_.path]; ret.profilepath = row[columns_.profilepath]; ret.imagetype = row[columns_.imagetype]; return ret; @@ -510,6 +529,12 @@ void DynamicProfilePanel::render_lens ( RENDER_OPTIONAL_ (lens); } +void DynamicProfilePanel::render_path ( + Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter) +{ + RENDER_OPTIONAL_ (path); +} + void DynamicProfilePanel::render_imagetype ( Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter) { diff --git a/rtgui/dynamicprofilepanel.h b/rtgui/dynamicprofilepanel.h index 972ca1c4a..03b9e7c62 100644 --- a/rtgui/dynamicprofilepanel.h +++ b/rtgui/dynamicprofilepanel.h @@ -55,6 +55,7 @@ private: add (expcomp); add (camera); add (lens); + add (path); add (profilepath); add (imagetype); } @@ -66,6 +67,7 @@ private: Gtk::TreeModelColumn> expcomp; Gtk::TreeModelColumn camera; Gtk::TreeModelColumn lens; + Gtk::TreeModelColumn path; Gtk::TreeModelColumn imagetype; Gtk::TreeModelColumn profilepath; }; @@ -78,6 +80,7 @@ private: void render_expcomp (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); void render_camera (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); void render_lens (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); + void render_path (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); void render_imagetype (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); void render_profilepath (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); @@ -114,6 +117,9 @@ private: Gtk::CheckButton *has_lens_; Gtk::Entry *lens_; + Gtk::CheckButton *has_path_; + Gtk::Entry *path_; + MyComboBoxText *imagetype_; ProfileStoreComboBox *profilepath_; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index d21ef3917..757338273 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -39,11 +39,14 @@ #include "procparamchangers.h" #include "placesbrowser.h" #include "pathutils.h" +#include "rtappchooserdialog.h" #include "thumbnail.h" #include "toolpanelcoord.h" #ifdef WIN32 #include "windows.h" + +#include "../rtengine/winutils.h" #endif using namespace rtengine::procparams; @@ -134,6 +137,235 @@ bool find_default_monitor_profile (GdkWindow *rootwin, Glib::ustring &defprof, G } #endif +bool hasUserOnlyPermission(const Glib::ustring &dirname) +{ +#if defined(__linux__) || defined(__APPLE__) + const Glib::RefPtr file = Gio::File::create_for_path(dirname); + const Glib::RefPtr file_info = file->query_info("owner::user,unix::mode"); + + if (!file_info) { + return false; + } + + const Glib::ustring owner = file_info->get_attribute_string("owner::user"); + const guint32 mode = file_info->get_attribute_uint32("unix::mode"); + + return (mode & 0777) == 0700 && owner == Glib::get_user_name(); +#elif defined(WIN32) + const Glib::RefPtr file = Gio::File::create_for_path(dirname); + const Glib::RefPtr file_info = file->query_info("owner::user"); + if (!file_info) { + return false; + } + + // Current user must be the owner. + const Glib::ustring user_name = Glib::get_user_name(); + const Glib::ustring owner = file_info->get_attribute_string("owner::user"); + if (user_name != owner) { + return false; + } + + // Get security descriptor and discretionary access control list. + PACL dacl = nullptr; + PSECURITY_DESCRIPTOR sec_desc_raw_ptr = nullptr; + auto win_error = GetNamedSecurityInfo( + dirname.c_str(), + SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION, + nullptr, + nullptr, + &dacl, + nullptr, + &sec_desc_raw_ptr + ); + const WinLocalPtr sec_desc_ptr(sec_desc_raw_ptr); + if (win_error != ERROR_SUCCESS) { + return false; + } + + // Must not inherit permissions. + SECURITY_DESCRIPTOR_CONTROL sec_desc_control; + DWORD revision; + if (!( + GetSecurityDescriptorControl(sec_desc_ptr, &sec_desc_control, &revision) + && sec_desc_control & SE_DACL_PROTECTED + )) { + return false; + } + + // Check that there is one entry allowing full access. + ULONG acl_entry_count; + PEXPLICIT_ACCESS acl_entry_list_raw = nullptr; + win_error = GetExplicitEntriesFromAcl(dacl, &acl_entry_count, &acl_entry_list_raw); + const WinLocalPtr acl_entry_list(acl_entry_list_raw); + if (win_error != ERROR_SUCCESS || acl_entry_count != 1) { + return false; + } + const EXPLICIT_ACCESS &ace = acl_entry_list[0]; + if ( + ace.grfAccessMode != GRANT_ACCESS + || (ace.grfAccessPermissions & FILE_ALL_ACCESS) != FILE_ALL_ACCESS + || ace.Trustee.TrusteeForm != TRUSTEE_IS_SID // Should already be SID, but double check. + ) { + return false; + } + + // ACE must be for the current user. + HANDLE process_token_raw; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &process_token_raw)) { + return false; + } + const WinHandle process_token(process_token_raw); + DWORD actual_token_info_size = 0; + GetTokenInformation(process_token, TokenUser, nullptr, 0, &actual_token_info_size); + if (!actual_token_info_size) { + return false; + } + const WinHeapPtr user_token_ptr(actual_token_info_size); + if (!user_token_ptr || !GetTokenInformation( + process_token, + TokenUser, + user_token_ptr, + actual_token_info_size, + &actual_token_info_size + )) { + return false; + } + return EqualSid(ace.Trustee.ptstrName, user_token_ptr->User.Sid); +#endif + return false; +} + +/** + * Sets read and write permissions, and optionally the execute permission, for + * the user and no permissions for others. + */ +void setUserOnlyPermission(const Glib::RefPtr file, bool execute) +{ +#if defined(__linux__) || defined(__APPLE__) + const Glib::RefPtr file_info = file->query_info("unix::mode"); + if (!file_info) { + return; + } + + guint32 mode = file_info->get_attribute_uint32("unix::mode"); + mode = (mode & ~0777) | (execute ? 0700 : 0600); + try { + file->set_attribute_uint32("unix::mode", mode, Gio::FILE_QUERY_INFO_NONE); + } catch (Gio::Error &) { + } +#elif defined(WIN32) + // Get the current user's SID. + HANDLE process_token_raw; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &process_token_raw)) { + return; + } + const WinHandle process_token(process_token_raw); + DWORD actual_token_info_size = 0; + GetTokenInformation(process_token, TokenUser, nullptr, 0, &actual_token_info_size); + if (!actual_token_info_size) { + return; + } + const WinHeapPtr user_token_ptr(actual_token_info_size); + if (!user_token_ptr || !GetTokenInformation( + process_token, + TokenUser, + user_token_ptr, + actual_token_info_size, + &actual_token_info_size + )) { + return; + } + const PSID user_sid = user_token_ptr->User.Sid; + + // Get a handle to the file. + const Glib::ustring filename = file->get_path(); + const HANDLE file_handle_raw = CreateFile( + filename.c_str(), + READ_CONTROL | WRITE_DAC, + 0, + nullptr, + OPEN_EXISTING, + execute ? FILE_FLAG_BACKUP_SEMANTICS : FILE_ATTRIBUTE_NORMAL, + nullptr + ); + if (file_handle_raw == INVALID_HANDLE_VALUE) { + return; + } + const WinHandle file_handle(file_handle_raw); + + // Create the user-only permission and set it. + EXPLICIT_ACCESS ea = { + .grfAccessPermissions = FILE_ALL_ACCESS, + .grfAccessMode = GRANT_ACCESS, + .grfInheritance = NO_INHERITANCE, + }; + BuildTrusteeWithSid(&(ea.Trustee), user_sid); + PACL new_dacl_raw = nullptr; + auto win_error = SetEntriesInAcl(1, &ea, nullptr, &new_dacl_raw); + if (win_error != ERROR_SUCCESS) { + return; + } + const WinLocalPtr new_dacl(new_dacl_raw); + SetSecurityInfo( + file_handle, + SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, + nullptr, + nullptr, + new_dacl, + nullptr + ); +#endif +} + +/** + * Gets the path to the temp directory, creating it if necessary. + */ +Glib::ustring getTmpDirectory() +{ +#if defined(__linux__) || defined(__APPLE__) || defined(WIN32) + static Glib::ustring recent_dir = ""; + const Glib::ustring tmp_dir_root = Glib::get_tmp_dir(); + const Glib::ustring subdir_base = + Glib::ustring::compose("rawtherapee-%1", Glib::get_user_name()); + Glib::ustring dir = Glib::build_filename(tmp_dir_root, subdir_base); + + // Returns true if the directory doesn't exist or has the right permissions. + auto is_usable_dir = [](const Glib::ustring &dir_path) { + return !Glib::file_test(dir_path, Glib::FILE_TEST_EXISTS) || (Glib::file_test(dir_path, Glib::FILE_TEST_IS_DIR) && hasUserOnlyPermission(dir_path)); + }; + + if (!(is_usable_dir(dir) || recent_dir.empty())) { + // Try to reuse the random suffix directory. + dir = recent_dir; + } + + if (!is_usable_dir(dir)) { + // Create new directory with random suffix. + gchar *const rand_dir = g_dir_make_tmp((subdir_base + "-XXXXXX").c_str(), nullptr); + if (!rand_dir) { + return tmp_dir_root; + } + dir = recent_dir = rand_dir; + g_free(rand_dir); + Glib::RefPtr file = Gio::File::create_for_path(dir); + setUserOnlyPermission(file, true); + } else if (!Glib::file_test(dir, Glib::FILE_TEST_EXISTS)) { + // Create the directory. + Glib::RefPtr file = Gio::File::create_for_path(dir); + bool dir_created = file->make_directory(); + if (!dir_created) { + return tmp_dir_root; + } + setUserOnlyPermission(file, true); + } + + return dir; +#else + return Glib::get_tmp_dir(); +#endif +} } class EditorPanel::ColorManagementToolbar @@ -470,7 +702,9 @@ public: EditorPanel::EditorPanel (FilePanel* filePanel) : catalogPane (nullptr), realized (false), tbBeforeLock (nullptr), iHistoryShow (nullptr), iHistoryHide (nullptr), iTopPanel_1_Show (nullptr), iTopPanel_1_Hide (nullptr), iRightPanel_1_Show (nullptr), iRightPanel_1_Hide (nullptr), - iBeforeLockON (nullptr), iBeforeLockOFF (nullptr), previewHandler (nullptr), beforePreviewHandler (nullptr), + iBeforeLockON (nullptr), iBeforeLockOFF (nullptr), + externalEditorChangedSignal (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), @@ -668,12 +902,14 @@ EditorPanel::EditorPanel (FilePanel* filePanel) queueimg->set_tooltip_markup (M ("MAIN_BUTTON_PUTTOQUEUE_TOOLTIP")); setExpandAlignProperties (queueimg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - Gtk::Image *sendToEditorButtonImage = Gtk::manage (new RTImage ("palette-brush", Gtk::ICON_SIZE_LARGE_TOOLBAR)); - sendtogimp = Gtk::manage (new Gtk::Button ()); - sendtogimp->set_relief(Gtk::RELIEF_NONE); - sendtogimp->add (*sendToEditorButtonImage); - sendtogimp->set_tooltip_markup (M ("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP")); - setExpandAlignProperties (sendtogimp, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); + send_to_external = Gtk::manage(new PopUpButton("", false)); + send_to_external->set_tooltip_text(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP")); + setExpandAlignProperties(send_to_external->buttonGroup, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); + updateExternalEditorWidget( + options.externalEditorIndex >= 0 ? options.externalEditorIndex : options.externalEditors.size(), + options.externalEditors + ); + send_to_external->show(); // Status box progressLabel = Gtk::manage (new MyProgressBar (300)); @@ -738,7 +974,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) iops->attach_next_to (*vsep1, Gtk::POS_LEFT, 1, 1); if (!gimpPlugin) { - iops->attach_next_to (*sendtogimp, Gtk::POS_LEFT, 1, 1); + iops->attach_next_to(*send_to_external->buttonGroup, Gtk::POS_LEFT, 1, 1); } if (!gimpPlugin && !simpleEditor) { @@ -842,7 +1078,8 @@ EditorPanel::EditorPanel (FilePanel* filePanel) tbRightPanel_1->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::tbRightPanel_1_toggled) ); saveimgas->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::saveAsPressed) ); queueimg->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::queueImgPressed) ); - sendtogimp->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::sendToGimpPressed) ); + send_to_external->signal_changed().connect(sigc::mem_fun(*this, &EditorPanel::sendToExternalChanged)); + send_to_external->signal_pressed().connect(sigc::mem_fun(*this, &EditorPanel::sendToExternalPressed)); toggleHistogramProfile->signal_toggled().connect( sigc::mem_fun (*this, &EditorPanel::histogramProfile_toggled) ); if (navPrev) { @@ -1675,7 +1912,7 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) case GDK_KEY_e: if (!gimpPlugin) { - sendToGimpPressed(); + sendToExternalPressed(); } return true; @@ -1776,7 +2013,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector *pc, img->setSaveProgressListener (parent->getProgressListener()); if (sf.format == "tif") - ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fname, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed), + ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fname, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed, sf.bigTiff), sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams)); else if (sf.format == "png") ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsPNG), fname, sf.pngBits), @@ -1793,7 +2030,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector *pc, msgd.run (); saveimgas->set_sensitive (true); - sendtogimp->set_sensitive (true); + send_to_external->set_sensitive(true); isProcessing = false; } @@ -1821,7 +2058,7 @@ bool EditorPanel::idle_imageSaved (ProgressConnector *pc, rtengine::IImagef } saveimgas->set_sensitive (true); - sendtogimp->set_sensitive (true); + send_to_external->set_sensitive(true); parent->setProgressStr (""); parent->setProgress (0.); @@ -1932,7 +2169,7 @@ void EditorPanel::saveAsPressed () ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ), sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_saveImage ), ld, fnameOut, sf, pparams)); saveimgas->set_sensitive (false); - sendtogimp->set_sensitive (false); + send_to_external->set_sensitive(false); } } else { BatchQueueEntry* bqe = createBatchQueueEntry (); @@ -1963,7 +2200,7 @@ void EditorPanel::queueImgPressed () parent->addBatchQueueJob (createBatchQueueEntry ()); } -void EditorPanel::sendToGimpPressed () +void EditorPanel::sendToExternal() { if (!ipc || !openThm) { return; @@ -1975,12 +2212,46 @@ void EditorPanel::sendToGimpPressed () if (options.editor_bypass_output_profile) { pparams.icm.outputProfile = rtengine::procparams::ColorManagementParams::NoProfileString; } + + if (!cached_exported_filename.empty() && cached_exported_image == ipc->getInitialImage() && pparams == cached_exported_pparams && Glib::file_test(cached_exported_filename, Glib::FILE_TEST_IS_REGULAR)) { + idle_sentToGimp(nullptr, nullptr, cached_exported_filename); + return; + } + + cached_exported_image = ipc->getInitialImage(); + cached_exported_pparams = pparams; + cached_exported_filename.clear(); rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); ProgressConnector *ld = new ProgressConnector(); ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ), sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_sendToGimp ), ld, openThm->getFileName() )); saveimgas->set_sensitive (false); - sendtogimp->set_sensitive (false); + send_to_external->set_sensitive(false); +} + +void EditorPanel::sendToExternalChanged(int) +{ + int index = send_to_external->getSelected(); + if (index >= 0 && static_cast(index) == options.externalEditors.size()) { + index = -1; + } + options.externalEditorIndex = index; + if (externalEditorChangedSignal) { + externalEditorChangedSignal->emit(); + } +} + +void EditorPanel::sendToExternalPressed() +{ + if (options.externalEditorIndex == -1) { + // "Other" external editor. Show app chooser dialog to let user pick. + RTAppChooserDialog *dialog = getAppChooserDialog(); + dialog->show(); + } else { + struct ExternalEditor editor = options.externalEditors.at(options.externalEditorIndex); + external_editor_info = Gio::AppInfo::create_from_commandline(editor.command, editor.name, Gio::APP_INFO_CREATE_NONE); + sendToExternal(); + } } @@ -1999,7 +2270,7 @@ bool EditorPanel::saveImmediately (const Glib::ustring &filename, const SaveForm if (gimpPlugin) { err = img->saveAsTIFF (filename, 32, true, true); } else if (sf.format == "tif") { - err = img->saveAsTIFF (filename, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed); + err = img->saveAsTIFF (filename, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed, sf.bigTiff); } else if (sf.format == "png") { err = img->saveAsPNG (filename, sf.pngBits); } else if (sf.format == "jpg") { @@ -2034,6 +2305,23 @@ void EditorPanel::syncFileBrowser() // synchronize filebrowser with image in E } } +ExternalEditorChangedSignal * EditorPanel::getExternalEditorChangedSignal() +{ + return externalEditorChangedSignal; +} + +void EditorPanel::setExternalEditorChangedSignal(ExternalEditorChangedSignal *signal) +{ + if (externalEditorChangedSignal) { + externalEditorChangedSignalConnection.disconnect(); + } + externalEditorChangedSignal = signal; + if (signal) { + externalEditorChangedSignalConnection = signal->connect( + sigc::mem_fun(*this, &EditorPanel::updateExternalEditorSelection)); + } +} + void EditorPanel::histogramProfile_toggled() { options.rtSettings.HistogramWorking = toggleHistogramProfile->get_active(); @@ -2058,7 +2346,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p dirname = options.editor_custom_out_dir; break; default: // Options::EDITOR_OUT_DIR_TEMP - dirname = Glib::get_tmp_dir(); + dirname = getTmpDirectory(); break; } Glib::ustring fullFileName = Glib::build_filename(dirname, shortname); @@ -2092,14 +2380,14 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p ProgressConnector *ld = new ProgressConnector(); img->setSaveProgressListener (parent->getProgressListener()); - ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fileName, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed), + ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fileName, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed, sf.bigTiff), sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_sentToGimp), ld, img, fileName)); } else { Glib::ustring msg_ = Glib::ustring (" Error during image processing\n"); Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); msgd.run (); saveimgas->set_sensitive (true); - sendtogimp->set_sensitive (true); + send_to_external->set_sensitive(true); } return false; @@ -2107,25 +2395,27 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring filename) { - delete img; - int errore = pc->returnValue(); + if (img) { + delete img; + cached_exported_filename = filename; + } + int errore = 0; setProgressState(false); - delete pc; + if (pc) { + errore = pc->returnValue(); + delete pc; + } - if (!errore) { + if ((!img && Glib::file_test(filename, Glib::FILE_TEST_IS_REGULAR)) || (img && !errore)) { saveimgas->set_sensitive (true); - sendtogimp->set_sensitive (true); + send_to_external->set_sensitive(true); parent->setProgressStr (""); parent->setProgress (0.); bool success = false; - if (options.editorToSendTo == 1) { - success = ExtProgStore::openInGimp (filename); - } else if (options.editorToSendTo == 2) { - success = ExtProgStore::openInPhotoshop (filename); - } else if (options.editorToSendTo == 3) { - success = ExtProgStore::openInCustomEditor (filename); - } + setUserOnlyPermission(Gio::File::create_for_path(filename), false); + + success = ExtProgStore::openInExternalEditor(filename, external_editor_info); if (!success) { Gtk::MessageDialog msgd (*parent, M ("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); @@ -2138,6 +2428,48 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagef return false; } +RTAppChooserDialog *EditorPanel::getAppChooserDialog() +{ + if (!app_chooser_dialog.get()) { + app_chooser_dialog.reset(new RTAppChooserDialog("image/tiff")); + app_chooser_dialog->signal_response().connect( + sigc::mem_fun(*this, &EditorPanel::onAppChooserDialogResponse) + ); + app_chooser_dialog->set_modal(); + } + + return app_chooser_dialog.get(); +} + +void EditorPanel::onAppChooserDialogResponse(int responseId) +{ + switch (responseId) { + case Gtk::RESPONSE_OK: + getAppChooserDialog()->close(); + external_editor_info = getAppChooserDialog()->get_app_info(); + sendToExternal(); + break; + case Gtk::RESPONSE_CANCEL: + case Gtk::RESPONSE_CLOSE: + getAppChooserDialog()->close(); + break; + default: + break; + } +} + +void EditorPanel::updateExternalEditorSelection() +{ + int index = send_to_external->getSelected(); + if (index >= 0 && static_cast(index) == options.externalEditors.size()) { + index = -1; + } + if (options.externalEditorIndex != index) { + send_to_external->setSelected( + options.externalEditorIndex >= 0 ? options.externalEditorIndex : options.externalEditors.size()); + } +} + void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) { @@ -2413,6 +2745,45 @@ void EditorPanel::tbShowHideSidePanels_managestate() ShowHideSidePanelsconn.block (false); } +void EditorPanel::updateExternalEditorWidget(int selectedIndex, const std::vector &editors) +{ + // Remove the editors. + while (send_to_external->getEntryCount()) { + send_to_external->removeEntry(send_to_external->getEntryCount() - 1); + } + + // Create new radio button group because they cannot be reused: https://developer-old.gnome.org/gtkmm/3.16/classGtk_1_1RadioButtonGroup.html#details. + send_to_external_radio_group = Gtk::RadioButtonGroup(); + + // Add the editors. + for (unsigned i = 0; i < editors.size(); i++) { + const auto & name = editors[i].name.empty() ? Glib::ustring(" ") : editors[i].name; + if (!editors[i].icon_serialized.empty()) { + Glib::RefPtr gioIcon; + GError *e = nullptr; + GVariant *icon_variant = g_variant_parse( + nullptr, editors[i].icon_serialized.c_str(), nullptr, nullptr, &e); + + if (e) { + std::cerr + << "Error loading external editor icon from \"" + << editors[i].icon_serialized << "\": " << e->message + << std::endl; + gioIcon = Glib::RefPtr(); + } else { + gioIcon = Gio::Icon::deserialize(Glib::VariantBase(icon_variant)); + } + + send_to_external->insertEntry(i, gioIcon, name, &send_to_external_radio_group); + } else { + send_to_external->insertEntry(i, "palette-brush", name, &send_to_external_radio_group); + } + } + send_to_external->addEntry("palette-brush", M("GENERAL_OTHER"), &send_to_external_radio_group); + send_to_external->setSelected(selectedIndex); + send_to_external->show(); +} + void EditorPanel::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC) { } @@ -2486,6 +2857,13 @@ void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition) } +void EditorPanel::updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools) +{ + if (tpc) { + tpc->updateToolLocations(favorites, cloneFavoriteTools); + } +} void EditorPanel::defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile) { diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 7675face5..98a475a7c 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -38,11 +38,15 @@ template class array2D; } +using ExternalEditorChangedSignal = sigc::signal; + class BatchQueueEntry; class EditorPanel; class FilePanel; class MyProgressBar; class Navigator; +class PopUpButton; +class RTAppChooserDialog; class Thumbnail; class ToolPanelCoordinator; @@ -65,6 +69,7 @@ class EditorPanel final : public rtengine::NonCopyable { public: + explicit EditorPanel (FilePanel* filePanel = nullptr); ~EditorPanel () override; @@ -162,11 +167,17 @@ public: void tbBeforeLock_toggled(); void saveAsPressed (); void queueImgPressed (); - void sendToGimpPressed (); + void sendToExternal(); + void sendToExternalChanged(int); + void sendToExternalPressed(); void openNextEditorImage (); void openPreviousEditorImage (); void syncFileBrowser (); + // Signals. + ExternalEditorChangedSignal * getExternalEditorChangedSignal(); + void setExternalEditorChangedSignal(ExternalEditorChangedSignal *signal); + void tbTopPanel_1_visible (bool visible); bool CheckSidePanelsVisibility(); void tbShowHideSidePanels_managestate(); @@ -182,9 +193,12 @@ public: { return isProcessing; } + void updateExternalEditorWidget(int selectedIndex, const std::vector &editors); void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC); void updateTPVScrollbar (bool hide); void updateHistogramPosition (int oldPosition, int newPosition); + void updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); void defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile); @@ -201,6 +215,9 @@ private: bool idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname); bool idle_sentToGimp (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring filename); void histogramProfile_toggled (); + RTAppChooserDialog *getAppChooserDialog(); + void onAppChooserDialogResponse(int resposneId); + void updateExternalEditorSelection(); Glib::ustring lastSaveAsFileName; @@ -230,10 +247,19 @@ private: Gtk::Button* queueimg; Gtk::Button* saveimgas; - Gtk::Button* sendtogimp; + PopUpButton* send_to_external; + Gtk::RadioButtonGroup send_to_external_radio_group; Gtk::Button* navSync; Gtk::Button* navNext; Gtk::Button* navPrev; + Glib::RefPtr external_editor_info; + std::unique_ptr app_chooser_dialog; + ExternalEditorChangedSignal *externalEditorChangedSignal; + sigc::connection externalEditorChangedSignalConnection; + + rtengine::InitialImage *cached_exported_image; + rtengine::procparams::ProcParams cached_exported_pparams; + Glib::ustring cached_exported_filename; class ColorManagementToolbar; std::unique_ptr colorMgmtToolBar; diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc index 5b57e35c7..365bf2ce6 100644 --- a/rtgui/editwindow.cc +++ b/rtgui/editwindow.cc @@ -201,6 +201,7 @@ void EditWindow::addEditorPanel (EditorPanel* ep, const std::string &name) { ep->setParent (parent); ep->setParentWindow(this); + ep->setExternalEditorChangedSignal(&externalEditorChangedSignal); // construct closeable tab for the image Gtk::Box* hb = Gtk::manage (new Gtk::Box ()); @@ -239,6 +240,7 @@ void EditWindow::remEditorPanel (EditorPanel* ep) return; // Will crash if destroyed while loading } + ep->setExternalEditorChangedSignal(nullptr); epanels.erase (ep->getFileName()); filesEdited.erase (ep->getFileName ()); parent->fpanel->refreshEditedState (filesEdited); @@ -436,3 +438,11 @@ void EditWindow::set_title_decorated(Glib::ustring fname) set_title("RawTherapee " + M("EDITWINDOW_TITLE") + subtitle); } + +void EditWindow::updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools) +{ + for (const auto& panel : epanels) { + panel.second->updateToolPanelToolLocations(favorites, cloneFavoriteTools); + } +} diff --git a/rtgui/editwindow.h b/rtgui/editwindow.h index bbe9a14c2..5d152879f 100644 --- a/rtgui/editwindow.h +++ b/rtgui/editwindow.h @@ -38,6 +38,8 @@ private: std::set filesEdited; std::map epanels; + sigc::signal externalEditorChangedSignal; + bool isFullscreen; bool isClosed; bool isMinimized; @@ -61,6 +63,8 @@ public: bool selectEditorPanel(const std::string &name); bool closeOpenEditors(); bool isProcessing(); + void updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); void toFront(); bool keyPressed (GdkEventKey* event); diff --git a/rtgui/epd.cc b/rtgui/epd.cc index d032cf28d..073c5ecdd 100644 --- a/rtgui/epd.cc +++ b/rtgui/epd.cc @@ -26,7 +26,9 @@ using namespace rtengine; using namespace rtengine::procparams; -EdgePreservingDecompositionUI::EdgePreservingDecompositionUI () : FoldableToolPanel(this, "epd", M("TP_EPD_LABEL"), true, true) +const Glib::ustring EdgePreservingDecompositionUI::TOOL_NAME = "epd"; + +EdgePreservingDecompositionUI::EdgePreservingDecompositionUI () : FoldableToolPanel(this, TOOL_NAME, M("TP_EPD_LABEL"), true, true) { strength = Gtk::manage(new Adjuster (M("TP_EPD_STRENGTH"), -1.0, 2.0, 0.01, 0.5)); diff --git a/rtgui/epd.h b/rtgui/epd.h index 6a5160623..1d866d690 100644 --- a/rtgui/epd.h +++ b/rtgui/epd.h @@ -36,6 +36,7 @@ protected: Adjuster *reweightingIterates; public: + static const Glib::ustring TOOL_NAME; EdgePreservingDecompositionUI(); diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc new file mode 100644 index 000000000..79dac52d2 --- /dev/null +++ b/rtgui/externaleditorpreferences.cc @@ -0,0 +1,358 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 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 +#include +#include +#include + +#include "externaleditorpreferences.h" +#include "multilangmgr.h" +#include "rtimage.h" + + +ExternalEditorPreferences::ExternalEditorPreferences(): + Box(Gtk::Orientation::ORIENTATION_VERTICAL), + list_model(Gtk::ListStore::create(model_columns)), + toolbar(Gtk::Orientation::ORIENTATION_HORIZONTAL) +{ + // List view. + list_view = Gtk::manage(new Gtk::TreeView()); + list_view->set_model(list_model); + list_view->append_column(*Gtk::manage(makeAppColumn())); + list_view->append_column(*Gtk::manage(makeCommandColumn())); + + for (auto &&column : list_view->get_columns()) { + column->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_FIXED); + } + + list_view->set_grid_lines(Gtk::TREE_VIEW_GRID_LINES_VERTICAL); + list_view->set_reorderable(); + + // List scroll area. + list_scroll_area.set_hexpand(); + list_scroll_area.set_vexpand(); + list_scroll_area.add(*list_view); + + // Toolbar buttons. + auto add_image = Gtk::manage(new RTImage("add-small.png")); + auto remove_image = Gtk::manage(new RTImage("remove-small.png")); + button_add = Gtk::manage(new Gtk::Button()); + button_remove = Gtk::manage(new Gtk::Button()); + button_add->set_image(*add_image); + button_remove->set_image(*remove_image); + button_app_chooser = Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE"))); + button_file_chooser = Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE_FILE"))); + + button_app_chooser->signal_pressed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::openAppChooserDialog)); + button_add->signal_pressed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::addEditor)); + button_file_chooser->signal_pressed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::openFileChooserDialog)); + button_remove->signal_pressed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::removeSelectedEditors)); + + list_view->get_selection()->signal_changed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::updateToolbarSensitivity)); + updateToolbarSensitivity(); + + // Toolbar. + toolbar.set_halign(Gtk::Align::ALIGN_END); + toolbar.add(*button_app_chooser); + toolbar.add(*button_file_chooser); + toolbar.add(*button_add); + toolbar.add(*button_remove); + + // This widget's children. + add(list_scroll_area); + add(toolbar); + show_all(); +} + +std::vector +ExternalEditorPreferences::getEditors() const +{ + std::vector editors; + + auto children = list_model->children(); + + for (auto rowIter = children.begin(); rowIter != children.end(); rowIter++) { + const Gio::Icon *const icon = rowIter->get_value(model_columns.icon).get(); + const auto &icon_serialized = icon == nullptr ? "" : icon->serialize().print(); + editors.push_back(ExternalEditorPreferences::EditorInfo( + rowIter->get_value(model_columns.name), + rowIter->get_value(model_columns.command), + icon_serialized, + rowIter->get_value(model_columns.other_data) + )); + } + + return editors; +} + +void ExternalEditorPreferences::setEditors( + const std::vector &editors) +{ + list_model->clear(); + + for (const ExternalEditorPreferences::EditorInfo & editor : editors) { + auto row = *list_model->append(); + Glib::RefPtr icon; + + // Get icon. + if (editor.icon_serialized.empty()) { + icon = Glib::RefPtr(); + } else { + GError *e = nullptr; + GVariant *icon_variant = g_variant_parse( + nullptr, editor.icon_serialized.c_str(), nullptr, nullptr, &e); + if (e) { + std::cerr + << "Error loading external editor icon from \"" + << editor.icon_serialized << "\": " << e->message + << std::endl; + icon = Glib::RefPtr(); + } else { + icon = Gio::Icon::deserialize(Glib::VariantBase(icon_variant)); + } + } + + row[model_columns.name] = editor.name; + row[model_columns.icon] = icon; + row[model_columns.command] = editor.command; + row[model_columns.other_data] = editor.other_data; + } +} + +void ExternalEditorPreferences::addEditor() +{ + Gtk::TreeModel::Row row; + auto selected = list_view->get_selection()->get_selected_rows(); + + if (selected.size()) { + row = *list_model->insert_after(list_model->get_iter(selected.back())); + } else { + row = *list_model->append(); + } + + row[model_columns.name] = "-"; + list_view->get_selection()->select(row); +} + +Gtk::TreeViewColumn *ExternalEditorPreferences::makeAppColumn() +{ + auto name_renderer = Gtk::manage(new Gtk::CellRendererText()); + auto icon_renderer = Gtk::manage(new Gtk::CellRendererPixbuf()); + auto col = Gtk::manage(new Gtk::TreeViewColumn()); + + col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_NAME")); + col->set_resizable(); + col->pack_start(*icon_renderer, false); + col->pack_start(*name_renderer); + col->add_attribute(*icon_renderer, "gicon", model_columns.icon); + col->add_attribute(*name_renderer, "text", model_columns.name); + col->set_min_width(20); + + name_renderer->property_editable() = true; + name_renderer->signal_edited().connect( + sigc::mem_fun(*this, &ExternalEditorPreferences::setAppName)); + + return col; +} + +Gtk::TreeViewColumn *ExternalEditorPreferences::makeCommandColumn() +{ + auto command_renderer = Gtk::manage(new Gtk::CellRendererText()); + auto col = Gtk::manage(new Gtk::TreeViewColumn()); + + col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_COMMAND")); + col->pack_start(*command_renderer); + col->add_attribute(*command_renderer, "text", model_columns.command); + + command_renderer->property_editable() = true; + command_renderer->signal_edited().connect( + sigc::mem_fun(*this, &ExternalEditorPreferences::setAppCommand)); + + return col; +} + +void ExternalEditorPreferences::onAppChooserDialogResponse( + int response_id, RTAppChooserDialog *dialog) +{ + switch (response_id) { + case Gtk::RESPONSE_OK: + dialog->close(); + setApp(dialog->get_app_info()); + break; + + case Gtk::RESPONSE_CANCEL: + case Gtk::RESPONSE_CLOSE: + dialog->close(); + break; + + default: + break; + } +} + +void ExternalEditorPreferences::onFileChooserDialogResponse( + int response_id, Gtk::FileChooserDialog *dialog) +{ + switch (response_id) { + case Gtk::RESPONSE_OK: { + dialog->close(); + + auto selection = list_view->get_selection()->get_selected_rows(); + for (const auto &selected : selection) { + auto row = *list_model->get_iter(selected); + row[model_columns.icon] = Glib::RefPtr(nullptr); + row[model_columns.command] = +#ifdef WIN32 + '"' + dialog->get_filename() + '"'; +#else + Glib::shell_quote(dialog->get_filename()); +#endif + } + + break; + } + + case Gtk::RESPONSE_CANCEL: + case Gtk::RESPONSE_CLOSE: + dialog->close(); + break; + + default: + break; + } +} + +void ExternalEditorPreferences::openAppChooserDialog() +{ + if (app_chooser_dialog.get()) { + app_chooser_dialog->refresh(); + app_chooser_dialog->show(); + return; + } + + app_chooser_dialog.reset(new RTAppChooserDialog("image/tiff")); + app_chooser_dialog->signal_response().connect(sigc::bind( + sigc::mem_fun(*this, &ExternalEditorPreferences::onAppChooserDialogResponse), + app_chooser_dialog.get() + )); + app_chooser_dialog->set_modal(); + app_chooser_dialog->show(); +} + +void ExternalEditorPreferences::openFileChooserDialog() +{ + if (file_chooser_dialog.get()) { + file_chooser_dialog->show(); + return; + } + + file_chooser_dialog.reset(new Gtk::FileChooserDialog(M("PREFERENCES_EXTERNALEDITOR_CHANGE_FILE"))); + + const auto exe_filter = Gtk::FileFilter::create(); + exe_filter->set_name(M("FILECHOOSER_FILTER_EXECUTABLE")); + exe_filter->add_custom(Gtk::FILE_FILTER_MIME_TYPE, [](const Gtk::FileFilter::Info &info) { +#ifdef WIN32 + return info.mime_type == "application/x-msdownload"; +#else + return Gio::content_type_can_be_executable(info.mime_type); +#endif + }); + const auto all_filter = Gtk::FileFilter::create(); + all_filter->set_name(M("FILECHOOSER_FILTER_ANY")); + all_filter->add_pattern("*"); + file_chooser_dialog->add_filter(exe_filter); + file_chooser_dialog->add_filter(all_filter); + + file_chooser_dialog->signal_response().connect(sigc::bind( + sigc::mem_fun(*this, &ExternalEditorPreferences::onFileChooserDialogResponse), + file_chooser_dialog.get())); + file_chooser_dialog->set_modal(); + file_chooser_dialog->add_button(M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL); + file_chooser_dialog->add_button(M("GENERAL_OPEN"), Gtk::RESPONSE_OK); + file_chooser_dialog->show(); +} + +void ExternalEditorPreferences::removeSelectedEditors() +{ + auto selection = list_view->get_selection()->get_selected_rows(); + + for (const auto &selected : selection) { + list_model->erase(list_model->get_iter(selected)); + } +} + +void ExternalEditorPreferences::setApp(const Glib::RefPtr app_info) +{ + auto selection = list_view->get_selection()->get_selected_rows(); + + for (const auto &selected : selection) { + auto row = *list_model->get_iter(selected); + row[model_columns.icon] = app_info->get_icon(); + row[model_columns.name] = app_info->get_name(); + row[model_columns.command] = app_info->get_commandline(); + } +} + +void ExternalEditorPreferences::setAppCommand( + const Glib::ustring & path, const Glib::ustring & new_text) +{ + auto row_iter = list_model->get_iter(path); + + if (!row_iter->get_value(model_columns.command).compare(new_text)) { + return; + } + + row_iter->set_value(model_columns.command, new_text); + row_iter->set_value(model_columns.icon, Glib::RefPtr(nullptr)); +} + +void ExternalEditorPreferences::setAppName( + const Glib::ustring & path, const Glib::ustring & new_text) +{ + list_model->get_iter(path)->set_value(model_columns.name, new_text); +} + +void ExternalEditorPreferences::updateToolbarSensitivity() +{ + bool selected = list_view->get_selection()->count_selected_rows(); + button_app_chooser->set_sensitive(selected); + button_file_chooser->set_sensitive(selected); + button_remove->set_sensitive(selected); +} + +ExternalEditorPreferences::EditorInfo::EditorInfo( + Glib::ustring name, Glib::ustring command, Glib::ustring icon_serialized, void *other_data +) : name(name), icon_serialized(icon_serialized), command(command), other_data(other_data) +{ +} + +ExternalEditorPreferences::ModelColumns::ModelColumns() +{ + add(name); + add(icon); + add(command); + add(other_data); +} diff --git a/rtgui/externaleditorpreferences.h b/rtgui/externaleditorpreferences.h new file mode 100644 index 000000000..34658d942 --- /dev/null +++ b/rtgui/externaleditorpreferences.h @@ -0,0 +1,167 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 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 +#include +#include +#include +#include + +#include "rtappchooserdialog.h" + + +namespace Gtk +{ + +class FileChooserDialog; + +} + + +/** + * Widget for editing the external editors options. + */ +class ExternalEditorPreferences : public Gtk::Box +{ +public: + /** + * Data struct containing information about an external editor. + */ + struct EditorInfo { + explicit EditorInfo( + Glib::ustring name = Glib::ustring(), + Glib::ustring command = Glib::ustring(), + Glib::ustring icon_serialized = Glib::ustring(), + void *other_data = nullptr + ); + /** + * Name of the external editor. + */ + Glib::ustring name; + /** + * The string representation of the icon. See Gio::Icon::serialize(). + */ + Glib::ustring icon_serialized; + /** + * The commandline for running the program. See + * Gio::AppInfo::get_commandline() + */ + Glib::ustring command; + /** + * Holds any other data associated with the editor. For example, it can + * be used as a tag to uniquely identify the editor. + */ + void *other_data; + }; + + ExternalEditorPreferences(); + + /** + * Creates and returns a vector representing the external editors shown in + * this widget. + */ + std::vector getEditors() const; + /** + * Populates this widget with the external editors described in the + * argument. + */ + void setEditors(const std::vector &editors); + +private: + /** + * Model representing the data fields each external editor entry has. + */ + class ModelColumns : public Gtk::TreeModelColumnRecord + { + public: + ModelColumns(); + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn> icon; + Gtk::TreeModelColumn command; + Gtk::TreeModelColumn other_data; + }; + + ModelColumns model_columns; + Glib::RefPtr list_model; // The list of editors. + Gtk::ScrolledWindow list_scroll_area; // Allows the list to be scrolled. + Gtk::TreeView *list_view; // Widget for displaying the list. + Gtk::Box toolbar; // Contains buttons for editing the list. + Gtk::Button *button_app_chooser; + Gtk::Button *button_add; + Gtk::Button *button_file_chooser; + Gtk::Button *button_remove; + std::unique_ptr app_chooser_dialog; + std::unique_ptr file_chooser_dialog; + + /** + * Inserts a new editor entry after the current selection, or at the end if + * no editor is selected. + */ + void addEditor(); + /** + * Constructs the column for displaying the external editor name (and icon). + */ + Gtk::TreeViewColumn *makeAppColumn(); + /** + * Constructs the column for displaying an editable commandline. + */ + Gtk::TreeViewColumn *makeCommandColumn(); + /** + * Called when the user is done interacting with the app chooser dialog. + * Closes the dialog and updates the selected entry if an app was chosen. + */ + void onAppChooserDialogResponse(int responseId, RTAppChooserDialog *dialog); + /** + * Called when the user is done interacting with the file chooser dialog. + * Closes the dialog and updates the selected entry if a file was chosen. + */ + void onFileChooserDialogResponse(int responseId, Gtk::FileChooserDialog *dialog); + /** + * Shows the app chooser dialog. + */ + void openAppChooserDialog(); + /** + * Shows the file chooser dialog for picking an executable. + */ + void openFileChooserDialog(); + /** + * Removes all selected editors. + */ + void removeSelectedEditors(); + /** + * Sets the selected entries with the provided information. + */ + void setApp(const Glib::RefPtr app_info); + /** + * Updates the application command and removes the icon for the given row. + */ + void setAppCommand(const Glib::ustring & path, const Glib::ustring & new_text); + /** + * Updates the application name for the given row. + */ + void setAppName(const Glib::ustring & path, const Glib::ustring & new_text); + /** + * Sets the sensitivity of the widgets in the toolbar to reflect the current + * state of the list. For example, makes the remove button insensitive if no + * entries are selected. + */ + void updateToolbarSensitivity(); +}; diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index 34dd35e54..9ec87c548 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -318,24 +318,58 @@ bool ExtProgStore::openInPhotoshop (const Glib::ustring& fileName) return spawnCommandAsync (cmdLine); } -bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName) +bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName, const Glib::ustring* command) { + if (!command) { + command = &(options.customEditorProg); + } + #if defined WIN32 - const auto cmdLine = Glib::ustring("\"") + options.customEditorProg + Glib::ustring("\""); + const auto cmdLine = Glib::ustring("\"") + *command + Glib::ustring("\""); auto success = ShellExecute( NULL, "open", cmdLine.c_str(), ('"' + fileName + '"').c_str(), NULL, SW_SHOWNORMAL ); return (uintptr_t)success > 32; #elif defined __APPLE__ - const auto cmdLine = options.customEditorProg + Glib::ustring(" \"") + fileName + Glib::ustring("\""); + const auto cmdLine = *command + Glib::ustring(" \"") + fileName + Glib::ustring("\""); return spawnCommandAsync (cmdLine); #else - const auto cmdLine = options.customEditorProg + Glib::ustring(" ") + Glib::shell_quote(fileName); + const auto cmdLine = *command + Glib::ustring(" ") + Glib::shell_quote(fileName); return spawnCommandAsync (cmdLine); #endif } + +bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo) +{ + bool success = false; + + try { + success = editorInfo->launch(Gio::File::create_for_path(fileName)); + } catch (const Glib::Error &e) { + std::cerr + << "Error launching external editor.\n" + << "Error code #" << e.code() << ": " << e.what() + << std::endl; + success = false; + } + + if (success) { + return true; + } + + if (rtengine::settings->verbose) { + std::cout << "Unable to launch external editor with Gio. Trying custom launcher." << std::endl; + } + Glib::ustring command = editorInfo->get_commandline(); +#if defined WIN32 + if (command.length() > 2 && command[0] == '"' && command[command.length() - 1] == '"') { + command = command.substr(1, command.length() - 2); + } +#endif + return openInCustomEditor(fileName, &command); +} diff --git a/rtgui/extprog.h b/rtgui/extprog.h index c5e00bb1b..6547896ef 100644 --- a/rtgui/extprog.h +++ b/rtgui/extprog.h @@ -20,10 +20,16 @@ #include +#include #include #include "threadutils.h" +namespace Gio +{ + class AppInfo; +} + struct ExtProgAction { Glib::ustring filePathEXE; @@ -63,7 +69,8 @@ public: static bool openInGimp (const Glib::ustring& fileName); static bool openInPhotoshop (const Glib::ustring& fileName); - static bool openInCustomEditor (const Glib::ustring& fileName); + static bool openInCustomEditor (const Glib::ustring& fileName, const Glib::ustring* command = nullptr); + static bool openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo); }; #define extProgStore ExtProgStore::getInstance() diff --git a/rtgui/fattaltonemap.cc b/rtgui/fattaltonemap.cc index 1e3c7171a..23a3a4ddf 100644 --- a/rtgui/fattaltonemap.cc +++ b/rtgui/fattaltonemap.cc @@ -31,7 +31,9 @@ using namespace rtengine; using namespace rtengine::procparams; -FattalToneMapping::FattalToneMapping(): FoldableToolPanel(this, "fattal", M("TP_TM_FATTAL_LABEL"), true, true) +const Glib::ustring FattalToneMapping::TOOL_NAME = "fattal"; + +FattalToneMapping::FattalToneMapping(): FoldableToolPanel(this, TOOL_NAME, M("TP_TM_FATTAL_LABEL"), true, true) { auto m = ProcEventMapper::getInstance(); EvTMFattalAnchor = m->newEvent(HDR, "HISTORY_MSG_TM_FATTAL_ANCHOR"); diff --git a/rtgui/fattaltonemap.h b/rtgui/fattaltonemap.h index 3d36ec7d2..f5c19f15c 100644 --- a/rtgui/fattaltonemap.h +++ b/rtgui/fattaltonemap.h @@ -33,6 +33,7 @@ protected: rtengine::ProcEvent EvTMFattalAnchor; public: + static const Glib::ustring TOOL_NAME; FattalToneMapping(); diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 90010abfd..1d1ed1617 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -167,6 +167,41 @@ FileBrowser::FileBrowser () : pmenu->attach (*Gtk::manage(selall = new Gtk::MenuItem (M("FILEBROWSER_POPUPSELECTALL"))), 0, 1, p, p + 1); p++; + /*********************** + * sort + ***********************/ + const std::array cnameSortOrders = { + M("SORT_ASCENDING"), + M("SORT_DESCENDING"), + }; + + const std::array cnameSortMethods = { + M("SORT_BY_NAME"), + M("SORT_BY_DATE"), + M("SORT_BY_EXIF"), + M("SORT_BY_RANK"), + M("SORT_BY_LABEL"), + }; + + pmenu->attach (*Gtk::manage(menuSort = new Gtk::MenuItem (M("FILEBROWSER_POPUPSORTBY"))), 0, 1, p, p + 1); + p++; + Gtk::Menu* submenuSort = Gtk::manage (new Gtk::Menu ()); + Gtk::RadioButtonGroup sortOrderGroup, sortMethodGroup; + for (size_t i = 0; i < cnameSortOrders.size(); i++) { + submenuSort->attach (*Gtk::manage(sortOrder[i] = new Gtk::RadioMenuItem (sortOrderGroup, cnameSortOrders[i])), 0, 1, p, p + 1); + p++; + sortOrder[i]->set_active (i == options.sortDescending); + } + submenuSort->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p + 1); + p++; + for (size_t i = 0; i < cnameSortMethods.size(); i++) { + submenuSort->attach (*Gtk::manage(sortMethod[i] = new Gtk::RadioMenuItem (sortMethodGroup, cnameSortMethods[i])), 0, 1, p, p + 1); + p++; + sortMethod[i]->set_active (i == options.sortMethod); + } + submenuSort->show_all (); + menuSort->set_submenu (*submenuSort); + /*********************** * rank ***********************/ @@ -427,6 +462,14 @@ FileBrowser::FileBrowser () : inspect->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), inspect)); } + for (int i = 0; i < 2; i++) { + sortOrder[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), sortOrder[i])); + } + + for (int i = 0; i < Options::SORT_METHOD_COUNT; i++) { + sortMethod[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), sortMethod[i])); + } + for (int i = 0; i < 6; i++) { rank[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), rank[i])); } @@ -610,27 +653,7 @@ void FileBrowser::addEntry_ (FileBrowserEntry* entry) entry->getThumbButtonSet()->setButtonListener(this); entry->resize(getThumbnailHeight()); entry->filtered = !checkFilter(entry); - - // find place in abc order - { - MYWRITERLOCK(l, entryRW); - - fd.insert( - std::lower_bound( - fd.begin(), - fd.end(), - entry, - [](const ThumbBrowserEntryBase* a, const ThumbBrowserEntryBase* b) - { - return *a < *b; - } - ), - entry - ); - - initEntry(entry); - } - redraw(entry); + insertEntry(entry); } FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) @@ -724,6 +747,18 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) return; } + for (int i = 0; i < 2; i++) + if (m == sortOrder[i]) { + sortOrderRequested (i); + return; + } + + for (int i = 0; i < Options::SORT_METHOD_COUNT; i++) + if (m == sortMethod[i]) { + sortMethodRequested (i); + return; + } + for (int i = 0; i < 6; i++) if (m == rank[i]) { rankingRequested (mselected, i); @@ -1632,6 +1667,18 @@ void FileBrowser::fromTrashRequested (std::vector tbe) applyFilter (filter); } +void FileBrowser::sortMethodRequested (int method) +{ + options.sortMethod = Options::SortMethod(method); + resort (); +} + +void FileBrowser::sortOrderRequested (int order) +{ + options.sortDescending = !!order; + resort (); +} + void FileBrowser::rankingRequested (std::vector tbe, int rank) { diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index 4602ba9bb..0df1cf9eb 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -83,9 +83,12 @@ protected: Gtk::MenuItem* open; Gtk::MenuItem* inspect; Gtk::MenuItem* selall; + Gtk::RadioMenuItem* sortMethod[Options::SORT_METHOD_COUNT]; + Gtk::RadioMenuItem* sortOrder[2]; Gtk::MenuItem* copyTo; Gtk::MenuItem* moveTo; + Gtk::MenuItem* menuSort; Gtk::MenuItem* menuRank; Gtk::MenuItem* menuLabel; Gtk::MenuItem* menuFileOperations; @@ -131,6 +134,8 @@ protected: void toTrashRequested (std::vector tbe); void fromTrashRequested (std::vector tbe); + void sortMethodRequested (int method); + void sortOrderRequested (int order); void rankingRequested (std::vector tbe, int rank); void colorlabelRequested (std::vector tbe, int colorlabel); void requestRanking (int rank); diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index 504422d8d..551d79c0b 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -45,10 +45,8 @@ std::shared_ptr FileBrowserEntry::hdr(std::shared_ptr(null std::shared_ptr FileBrowserEntry::ps(std::shared_ptr(nullptr)); FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname) - : ThumbBrowserEntryBase (fname), wasInside(false), iatlistener(nullptr), press_x(0), press_y(0), action_x(0), action_y(0), rot_deg(0.0), landscape(true), cropParams(new rtengine::procparams::CropParams), cropgl(nullptr), state(SNormal), crop_custom_ratio(0.f) + : ThumbBrowserEntryBase (fname, thm), wasInside(false), iatlistener(nullptr), press_x(0), press_y(0), action_x(0), action_y(0), rot_deg(0.0), landscape(true), cropParams(new rtengine::procparams::CropParams), cropgl(nullptr), state(SNormal), crop_custom_ratio(0.f) { - thumbnail = thm; - feih = new FileBrowserEntryIdleHelper; feih->fbentry = this; feih->destroyed = false; diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index 9dc2a656c..adcd6985d 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -437,3 +437,11 @@ void FilePanel::updateTPVScrollbar (bool hide) { tpc->updateTPVScrollbar (hide); } + +void FilePanel::updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools) +{ + if (tpc) { + tpc->updateToolLocations(favorites, cloneFavoriteTools); + } +} diff --git a/rtgui/filepanel.h b/rtgui/filepanel.h index ba5dfa7c9..4a006f002 100644 --- a/rtgui/filepanel.h +++ b/rtgui/filepanel.h @@ -83,6 +83,8 @@ public: bool handleShortcutKey (GdkEventKey* event); bool handleShortcutKeyRelease(GdkEventKey *event); void updateTPVScrollbar (bool hide); + void updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); private: void on_NB_switch_page(Gtk::Widget* page, guint page_num); diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc index ad998a364..5bae5d795 100644 --- a/rtgui/filmnegative.cc +++ b/rtgui/filmnegative.cc @@ -28,6 +28,8 @@ #include "../rtengine/procparams.h" #include "../rtengine/color.h" +const Glib::ustring FilmNegative::TOOL_NAME = "filmnegative"; + namespace { @@ -184,7 +186,7 @@ void rgb2temp(const RGB &refOut, double &outLev, double &temp, double &green) } FilmNegative::FilmNegative() : - FoldableToolPanel(this, "filmnegative", M("TP_FILMNEGATIVE_LABEL"), false, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_FILMNEGATIVE_LABEL"), false, true), EditSubscriber(ET_OBJECTS), NEUTRAL_TEMP(rtengine::ColorTemp(1., 1., 1., 1.)), evFilmNegativeExponents(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_VALUES")), diff --git a/rtgui/filmnegative.h b/rtgui/filmnegative.h index 21a7dce5c..722625fa2 100644 --- a/rtgui/filmnegative.h +++ b/rtgui/filmnegative.h @@ -52,6 +52,8 @@ class FilmNegative final : public rtengine::FilmNegListener { public: + static const Glib::ustring TOOL_NAME; + FilmNegative(); ~FilmNegative() override; diff --git a/rtgui/filmsimulation.cc b/rtgui/filmsimulation.cc index d19c84c6f..fb38f87dc 100644 --- a/rtgui/filmsimulation.cc +++ b/rtgui/filmsimulation.cc @@ -12,6 +12,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring FilmSimulation::TOOL_NAME = "filmsimulation"; + namespace { @@ -61,7 +63,7 @@ bool notifySlowParseDir (const std::chrono::system_clock::time_point& startedAt) } FilmSimulation::FilmSimulation() - : FoldableToolPanel( this, "filmsimulation", M("TP_FILMSIMULATION_LABEL"), false, true ) + : FoldableToolPanel( this, TOOL_NAME, M("TP_FILMSIMULATION_LABEL"), false, true ) { m_clutComboBox = Gtk::manage( new ClutComboBox(options.clutsDir) ); diff --git a/rtgui/filmsimulation.h b/rtgui/filmsimulation.h index cfe7016bb..ed30b866e 100644 --- a/rtgui/filmsimulation.h +++ b/rtgui/filmsimulation.h @@ -56,6 +56,8 @@ private: class FilmSimulation : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { public: + static const Glib::ustring TOOL_NAME; + FilmSimulation(); void adjusterChanged(Adjuster* a, double newval) override; diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc index b217bb7c5..7c9f80cb1 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -18,6 +18,7 @@ */ #include +#include "eventmapper.h" #include "flatfield.h" #include "guiutils.h" @@ -30,8 +31,13 @@ using namespace rtengine; using namespace rtengine::procparams; -FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_LABEL")) +const Glib::ustring FlatField::TOOL_NAME = "flatfield"; + +FlatField::FlatField () : FoldableToolPanel(this, TOOL_NAME, M("TP_FLATFIELD_LABEL")) { + auto m = ProcEventMapper::getInstance(); + EvFlatFieldFromMetaData = m->newEvent(DARKFRAME, "HISTORY_MSG_FF_FROMMETADATA"); + hbff = Gtk::manage(new Gtk::Box()); flatFieldFile = Gtk::manage(new MyFileChooserButton(M("TP_FLATFIELD_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); bindCurrentFolder (*flatFieldFile, options.lastFlatfieldDir); @@ -42,6 +48,8 @@ FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_L hbff->pack_start(*flatFieldFile); hbff->pack_start(*flatFieldFileReset, Gtk::PACK_SHRINK); flatFieldAutoSelect = Gtk::manage(new Gtk::CheckButton((M("TP_FLATFIELD_AUTOSELECT")))); + flatFieldFromMetaData = Gtk::manage(new CheckBox((M("TP_FLATFIELD_FROMMETADATA")), multiImage)); + flatFieldFromMetaData->setCheckBoxListener (this); ffInfo = Gtk::manage(new Gtk::Label("-")); setExpandAlignProperties(ffInfo, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); flatFieldBlurRadius = Gtk::manage(new Adjuster (M("TP_FLATFIELD_BLURRADIUS"), 0, 200, 2, 32)); @@ -70,8 +78,10 @@ FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_L flatFieldClipControl->show(); flatFieldClipControl->set_tooltip_markup (M("TP_FLATFIELD_CLIPCONTROL_TOOLTIP")); - pack_start( *hbff, Gtk::PACK_SHRINK); + pack_start( *flatFieldFromMetaData, Gtk::PACK_SHRINK); + pack_start( *Gtk::manage( new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_SHRINK, 0 ); pack_start( *flatFieldAutoSelect, Gtk::PACK_SHRINK); + pack_start( *hbff, Gtk::PACK_SHRINK); pack_start( *ffInfo, Gtk::PACK_SHRINK); pack_start( *hbffbt, Gtk::PACK_SHRINK); pack_start( *flatFieldBlurRadius, Gtk::PACK_SHRINK); @@ -128,12 +138,14 @@ void FlatField::read(const rtengine::procparams::ProcParams* pp, const ParamsEdi } flatFieldAutoSelect->set_active (pp->raw.ff_AutoSelect); + flatFieldFromMetaData->set_active (pp->raw.ff_FromMetaData); flatFieldBlurRadius->setValue (pp->raw.ff_BlurRadius); flatFieldClipControl->setValue (pp->raw.ff_clipControl); flatFieldClipControl->setAutoValue (pp->raw.ff_AutoClipControl); if(pedited ) { flatFieldAutoSelect->set_inconsistent (!pedited->raw.ff_AutoSelect); + flatFieldFromMetaData->set_inconsistent (!pedited->raw.ff_FromMetaData); flatFieldBlurRadius->setEditedState( pedited->raw.ff_BlurRadius ? Edited : UnEdited ); flatFieldClipControl->setEditedState( pedited->raw.ff_clipControl ? Edited : UnEdited ); flatFieldClipControl->setAutoInconsistent(multiImage && !pedited->raw.ff_AutoClipControl); @@ -214,6 +226,7 @@ void FlatField::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedit { pp->raw.ff_file = flatFieldFile->get_filename(); pp->raw.ff_AutoSelect = flatFieldAutoSelect->get_active(); + pp->raw.ff_FromMetaData = flatFieldFromMetaData->get_active(); pp->raw.ff_BlurRadius = flatFieldBlurRadius->getIntValue(); pp->raw.ff_clipControl = flatFieldClipControl->getIntValue(); pp->raw.ff_AutoClipControl = flatFieldClipControl->getAutoValue(); @@ -227,6 +240,7 @@ void FlatField::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedit if (pedited) { pedited->raw.ff_file = ffChanged; pedited->raw.ff_AutoSelect = !flatFieldAutoSelect->get_inconsistent(); + pedited->raw.ff_FromMetaData = !flatFieldFromMetaData->get_inconsistent(); pedited->raw.ff_BlurRadius = flatFieldBlurRadius->getEditedState (); pedited->raw.ff_clipControl = flatFieldClipControl->getEditedState (); pedited->raw.ff_AutoClipControl = !flatFieldClipControl->getAutoInconsistent(); @@ -352,6 +366,13 @@ void FlatField::flatFieldBlurTypeChanged () } } +void FlatField::checkBoxToggled (CheckBox* c, CheckValue newval) +{ + if (listener && c == flatFieldFromMetaData) { + listener->panelChanged (EvFlatFieldFromMetaData, flatFieldFromMetaData->getLastActive() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + void FlatField::flatFieldAutoSelectChanged() { if (batchMode) { @@ -419,3 +440,18 @@ void FlatField::flatFieldAutoClipValueChanged(int n) } ); } + +void FlatField::setGainMap(bool enabled) { + flatFieldFromMetaData->set_sensitive(enabled); + if (!enabled) { + idle_register.add( + [this, enabled]() -> bool + { + disableListener(); + flatFieldFromMetaData->setValue(false); + enableListener(); + return false; + } + ); + } +} diff --git a/rtgui/flatfield.h b/rtgui/flatfield.h index 0d6f167e1..efb8a2cec 100644 --- a/rtgui/flatfield.h +++ b/rtgui/flatfield.h @@ -23,6 +23,7 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "guiutils.h" #include "toolpanel.h" @@ -42,7 +43,7 @@ public: // add other info here }; -class FlatField final : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::FlatFieldAutoClipListener +class FlatField final : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::FlatFieldAutoClipListener { protected: @@ -52,6 +53,7 @@ protected: Gtk::Label *ffInfo; Gtk::Button *flatFieldFileReset; Gtk::CheckButton* flatFieldAutoSelect; + CheckBox* flatFieldFromMetaData; Adjuster* flatFieldClipControl; Adjuster* flatFieldBlurRadius; MyComboBoxText* flatFieldBlurType; @@ -64,9 +66,12 @@ protected: Glib::ustring lastShortcutPath; bool b_filter_asCurrent; bool israw; + rtengine::ProcEvent EvFlatFieldFromMetaData; IdleRegister idle_register; + public: + static const Glib::ustring TOOL_NAME; FlatField (); ~FlatField () override; @@ -90,4 +95,6 @@ public: ffp = p; }; void flatFieldAutoClipValueChanged(int n = 0) override; + void checkBoxToggled(CheckBox* c, CheckValue newval) override; + void setGainMap(bool enabled); }; diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index 79f8d085f..98d5eb8d6 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -25,7 +25,9 @@ enum GeometryIndex { } -Gradient::Gradient () : FoldableToolPanel(this, "gradient", M("TP_GRADIENT_LABEL"), false, true), EditSubscriber(ET_OBJECTS), lastObject(-1), draggedPointOldAngle(-1000.) +const Glib::ustring Gradient::TOOL_NAME = "gradient"; + +Gradient::Gradient () : FoldableToolPanel(this, TOOL_NAME, M("TP_GRADIENT_LABEL"), false, true), EditSubscriber(ET_OBJECTS), lastObject(-1), draggedPointOldAngle(-1000.) { editHBox = Gtk::manage (new Gtk::Box()); diff --git a/rtgui/gradient.h b/rtgui/gradient.h index dc0371932..d7754007c 100644 --- a/rtgui/gradient.h +++ b/rtgui/gradient.h @@ -38,6 +38,7 @@ protected: void releaseEdit(); public: + static const Glib::ustring TOOL_NAME; Gradient (); ~Gradient () override; diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index c6399bed6..7197987cb 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -1495,33 +1495,110 @@ TextOrIcon::TextOrIcon (const Glib::ustring &icon_name, const Glib::ustring &lab } -MyImageMenuItem::MyImageMenuItem(Glib::ustring label, Glib::ustring iconName) +class ImageAndLabel::Impl { - box = Gtk::manage (new Gtk::Grid()); - this->label = Gtk::manage( new Gtk::Label(label)); - box->set_orientation(Gtk::ORIENTATION_HORIZONTAL); +public: + RTImage* image; + Gtk::Label* label; - if (!iconName.empty()) { - image = Gtk::manage( new RTImage(iconName, Gtk::ICON_SIZE_MENU) ); - box->attach_next_to(*image, Gtk::POS_LEFT, 1, 1); - } else { - image = nullptr; + Impl(RTImage* image, Gtk::Label* label) : image(image), label(label) {} + static std::unique_ptr createImage(const Glib::ustring& iconName); +}; + +std::unique_ptr ImageAndLabel::Impl::createImage(const Glib::ustring& iconName) +{ + if (iconName.empty()) { + return nullptr; + } + return std::unique_ptr(new RTImage(iconName, Gtk::ICON_SIZE_LARGE_TOOLBAR)); +} + +ImageAndLabel::ImageAndLabel(const Glib::ustring& label, const Glib::ustring& iconName) : + ImageAndLabel(label, Gtk::manage(Impl::createImage(iconName).release())) +{ +} + +ImageAndLabel::ImageAndLabel(const Glib::ustring& label, RTImage *image) : + pimpl(new Impl(image, Gtk::manage(new Gtk::Label(label)))) +{ + Gtk::Grid* grid = Gtk::manage(new Gtk::Grid()); + grid->set_orientation(Gtk::ORIENTATION_HORIZONTAL); + + if (image) { + grid->attach_next_to(*image, Gtk::POS_LEFT, 1, 1); } - box->attach_next_to(*this->label, Gtk::POS_RIGHT, 1, 1); - box->set_column_spacing(4); - box->set_row_spacing(0); - add(*box); + grid->attach_next_to(*(pimpl->label), Gtk::POS_RIGHT, 1, 1); + grid->set_column_spacing(4); + grid->set_row_spacing(0); + pack_start(*grid, Gtk::PACK_SHRINK, 0); +} + +const RTImage* ImageAndLabel::getImage() const +{ + return pimpl->image; +} + +const Gtk::Label* ImageAndLabel::getLabel() const +{ + return pimpl->label; +} + +class MyImageMenuItem::Impl +{ +private: + std::unique_ptr widget; + +public: + Impl(const Glib::ustring &label, const Glib::ustring &iconName) : + widget(new ImageAndLabel(label, iconName)) {} + Impl(const Glib::ustring &label, RTImage *itemImage) : + widget(new ImageAndLabel(label, itemImage)) {} + ImageAndLabel* getWidget() const { return widget.get(); } +}; + +MyImageMenuItem::MyImageMenuItem(const Glib::ustring& label, const Glib::ustring& iconName) : + pimpl(new Impl(label, iconName)) +{ + add(*(pimpl->getWidget())); +} + +MyImageMenuItem::MyImageMenuItem(const Glib::ustring& label, RTImage* itemImage) : + pimpl(new Impl(label, itemImage)) +{ + add(*(pimpl->getWidget())); } const RTImage *MyImageMenuItem::getImage () const { - return image; + return pimpl->getWidget()->getImage(); } const Gtk::Label* MyImageMenuItem::getLabel () const { - return label; + return pimpl->getWidget()->getLabel(); +} + +class MyRadioImageMenuItem::Impl +{ + std::unique_ptr widget; + +public: + Impl(const Glib::ustring &label, RTImage *image) : + widget(new ImageAndLabel(label, image)) {} + ImageAndLabel* getWidget() const { return widget.get(); } +}; + +MyRadioImageMenuItem::MyRadioImageMenuItem(const Glib::ustring& label, RTImage *image, Gtk::RadioButton::Group& group) : + Gtk::RadioMenuItem(group), + pimpl(new Impl(label, image)) +{ + add(*(pimpl->getWidget())); +} + +const Gtk::Label* MyRadioImageMenuItem::getLabel() const +{ + return pimpl->getWidget()->getLabel(); } MyProgressBar::MyProgressBar(int width) : w(rtengine::max(width, RTScalable::scalePixelSize(10))) {} diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 3b8e80ebb..c73f7f37c 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -20,6 +20,7 @@ #include #include +#include #include @@ -74,6 +75,17 @@ private: MyMutex mutex; }; +struct ScopedEnumHash { + template::value && !std::is_convertible::value, int>::type = 0> + size_t operator ()(T val) const noexcept + { + using type = typename std::underlying_type::type; + + return std::hash{}(static_cast(val)); + } +}; + + // TODO: The documentation says gdk_threads_enter and gdk_threads_leave should be replaced // by g_main_context_invoke(), g_idle_add() and related functions, but this will require more extensive changes. // We silence those warnings until then so that we notice the others. @@ -478,17 +490,56 @@ public: TextOrIcon (const Glib::ustring &icon_name, const Glib::ustring &labelTx, const Glib::ustring &tooltipTx); }; -class MyImageMenuItem final : public Gtk::MenuItem +/** + * Widget with image and label placed horizontally. + */ +class ImageAndLabel final : public Gtk::Box { -private: - Gtk::Grid *box; - RTImage *image; - Gtk::Label *label; + class Impl; + std::unique_ptr pimpl; public: - MyImageMenuItem (Glib::ustring label, Glib::ustring iconName); + ImageAndLabel(const Glib::ustring& label, const Glib::ustring& iconName); + ImageAndLabel(const Glib::ustring& label, RTImage* image); + const RTImage* getImage() const; + const Gtk::Label* getLabel() const; +}; + +/** + * Menu item with an image and label. + */ +class MyImageMenuItemInterface +{ +public: + virtual const Gtk::Label* getLabel() const = 0; +}; + +/** + * Basic image menu item. + */ +class MyImageMenuItem final : public Gtk::MenuItem, public MyImageMenuItemInterface +{ + class Impl; + std::unique_ptr pimpl; + +public: + MyImageMenuItem (const Glib::ustring& label, const Glib::ustring& iconName); + MyImageMenuItem (const Glib::ustring& label, RTImage* image); const RTImage *getImage () const; - const Gtk::Label* getLabel () const; + const Gtk::Label* getLabel() const override; +}; + +/** + * Image menu item with radio selector. + */ +class MyRadioImageMenuItem final : public Gtk::RadioMenuItem, public MyImageMenuItemInterface +{ + class Impl; + std::unique_ptr pimpl; + +public: + MyRadioImageMenuItem(const Glib::ustring& label, RTImage* image, Gtk::RadioButton::Group& group); + const Gtk::Label* getLabel() const override; }; class MyProgressBar final : public Gtk::ProgressBar diff --git a/rtgui/hsvequalizer.cc b/rtgui/hsvequalizer.cc index 817ba1f4d..ddb1d2fb5 100644 --- a/rtgui/hsvequalizer.cc +++ b/rtgui/hsvequalizer.cc @@ -28,9 +28,11 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring HSVEqualizer::TOOL_NAME = "hsvequalizer"; + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -HSVEqualizer::HSVEqualizer () : FoldableToolPanel(this, "hsvequalizer", M("TP_HSVEQUALIZER_LABEL"), false, true) +HSVEqualizer::HSVEqualizer () : FoldableToolPanel(this, TOOL_NAME, M("TP_HSVEQUALIZER_LABEL"), false, true) { std::vector bottomMilestones; diff --git a/rtgui/hsvequalizer.h b/rtgui/hsvequalizer.h index 77c1ee1b0..1f80cd9e4 100644 --- a/rtgui/hsvequalizer.h +++ b/rtgui/hsvequalizer.h @@ -44,6 +44,7 @@ protected: FlatCurveEditor* vshape; public: + static const Glib::ustring TOOL_NAME; HSVEqualizer (); ~HSVEqualizer () override; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index e5f3f328a..e79ef2cff 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -35,7 +35,9 @@ using namespace rtengine; using namespace rtengine::procparams; -ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunchanged(nullptr), icmplistener(nullptr) +const Glib::ustring ICMPanel::TOOL_NAME = "icm"; + +ICMPanel::ICMPanel() : FoldableToolPanel(this, TOOL_NAME, M("TP_ICM_LABEL")), iunchanged(nullptr), icmplistener(nullptr) { auto m = ProcEventMapper::getInstance(); EvICMprimariMethod = m->newEvent(GAMMA, "HISTORY_MSG_ICM_OUTPUT_PRIMARIES"); @@ -62,6 +64,7 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha EvICMpreser = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_PRESER"); EvICMLabGridciexy = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICL_LABGRIDCIEXY"); EvICMfbw = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_FBW"); + EvICMgamut = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_GAMUT"); isBatchMode = lastToneCurve = lastApplyLookTable = lastApplyBaselineExposureOffset = lastApplyHueSatMap = false; ipDialog = Gtk::manage(new MyFileChooserButton(M("TP_ICM_INPUTDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); @@ -263,8 +266,12 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha wprimBox->pack_start(*wprim, Gtk::PACK_EXPAND_WIDGET); fbw = Gtk::manage(new Gtk::CheckButton((M("TP_ICM_FBW")))); fbw->set_active(true); + gamut = Gtk::manage(new Gtk::CheckButton((M("TP_ICM_GAMUT")))); + gamut->set_active(false); + trcProfVBox->pack_start(*wprimBox, Gtk::PACK_EXPAND_WIDGET); trcProfVBox->pack_start(*fbw, Gtk::PACK_EXPAND_WIDGET); + trcProfVBox->pack_start(*gamut, Gtk::PACK_EXPAND_WIDGET); neutral = Gtk::manage (new Gtk::Button (M ("TP_ICM_NEUTRAL"))); setExpandAlignProperties (neutral, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); @@ -468,6 +475,7 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha wprimconn = wprim->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::wprimChanged)); fbwconn = fbw->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::fbwChanged)); + gamutconn = gamut->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::gamutChanged)); obpcconn = obpc->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::oBPCChanged)); tcurveconn = ckbToneCurve->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::toneCurveChanged)); ltableconn = ckbApplyLookTable->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::applyLookTableChanged)); @@ -513,6 +521,7 @@ void ICMPanel::neutral_pressed () wSlope->setValue(defPar.workingTRCSlope);//12.92 preser->setValue(defPar.preser); fbw->set_active(defPar.fbw); + gamut->set_active(defPar.gamut); wTRC->set_active(toUnderlying(ColorManagementParams::WorkingTrc::NONE));//reset to none will->set_active(toUnderlying(ColorManagementParams::Illuminant::DEFAULT));//reset to default - after wprim } @@ -765,6 +774,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) ConnectionBlocker obpcconn_(obpcconn); ConnectionBlocker fbwconn_(fbwconn); + ConnectionBlocker gamutconn_(gamutconn); ConnectionBlocker ipc_(ipc); ConnectionBlocker tcurveconn_(tcurveconn); ConnectionBlocker ltableconn_(ltableconn); @@ -838,6 +848,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) obpc->set_active(pp->icm.outputBPC); fbw->set_active(pp->icm.fbw); + gamut->set_active(pp->icm.gamut); ckbToneCurve->set_active(pp->icm.toneCurve); lastToneCurve = pp->icm.toneCurve; ckbApplyLookTable->set_active(pp->icm.applyLookTable); @@ -862,6 +873,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) iunchanged->set_active(!pedited->icm.inputProfile); obpc->set_inconsistent(!pedited->icm.outputBPC); fbw->set_inconsistent(!pedited->icm.fbw); + gamut->set_inconsistent(!pedited->icm.gamut); ckbToneCurve->set_inconsistent(!pedited->icm.toneCurve); ckbApplyLookTable->set_inconsistent(!pedited->icm.applyLookTable); ckbApplyBaselineExposureOffset->set_inconsistent(!pedited->icm.applyBaselineExposureOffset); @@ -920,6 +932,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(false); wprim->set_sensitive(false); fbw->set_sensitive(false); + gamut->set_sensitive(false); wprimlab->set_sensitive(false); riaHBox->set_sensitive(false); redFrame->hide(); @@ -931,6 +944,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { redFrame->hide(); @@ -973,6 +987,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -990,6 +1005,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1007,6 +1023,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); redFrame->show(); wGamma->set_sensitive(false); @@ -1025,6 +1042,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); riaHBox->set_sensitive(true); if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { @@ -1042,6 +1060,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1143,6 +1162,7 @@ void ICMPanel::write(ProcParams* pp, ParamsEdited* pedited) pp->icm.applyHueSatMap = ckbApplyHueSatMap->get_active(); pp->icm.outputBPC = obpc->get_active(); pp->icm.fbw = fbw->get_active(); + pp->icm.gamut = gamut->get_active(); pp->icm.workingTRCGamma = wGamma->getValue(); pp->icm.workingTRCSlope = wSlope->getValue(); pp->icm.redx = redx->getValue(); @@ -1162,6 +1182,7 @@ void ICMPanel::write(ProcParams* pp, ParamsEdited* pedited) pedited->icm.aRendIntent = aRendIntent->getSelected() < 4; pedited->icm.outputBPC = !obpc->get_inconsistent(); pedited->icm.fbw = !fbw->get_inconsistent(); + pedited->icm.gamut = !gamut->get_inconsistent(); pedited->icm.dcpIlluminant = dcpIll->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent(); pedited->icm.applyLookTable = !ckbApplyLookTable->get_inconsistent(); @@ -1268,6 +1289,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(false); wprim->set_sensitive(false); fbw->set_sensitive(false); + gamut->set_sensitive(false); wprimlab->set_sensitive(false); redFrame->hide(); riaHBox->set_sensitive(false); @@ -1278,6 +1300,7 @@ void ICMPanel::wtrcinChanged() will->set_sensitive(false); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); willulab->set_sensitive(true); if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { @@ -1311,6 +1334,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1336,6 +1360,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); riaHBox->set_sensitive(true); @@ -1362,6 +1387,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1389,6 +1415,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1416,6 +1443,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -2023,6 +2051,33 @@ void ICMPanel::fbwChanged() } } +void ICMPanel::gamutChanged() +{ + if (multiImage) { + if (gamut->get_inconsistent()) { + gamut->set_inconsistent(false); + gamutconn.block(true); + gamut->set_active(false); + gamutconn.block(false); + } else if (lastgamut) { + gamut->set_inconsistent(true); + } + + lastgamut = gamut->get_active(); + } + + if (listener) { + if (gamut->get_inconsistent()) { + listener->panelChanged(EvICMgamut, M("GENERAL_UNCHANGED")); + } else if (fbw->get_active()) { + listener->panelChanged(EvICMgamut, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(EvICMgamut, M("GENERAL_DISABLED")); + } + } +} + + void ICMPanel::setRawMeta(bool raw, const rtengine::FramesData* pMeta) { diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 8d52fb25f..6c670c5e6 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -81,6 +81,8 @@ protected: bool lastfbw; sigc::connection fbwconn; bool isBatchMode; + bool lastgamut; + sigc::connection gamutconn; private: rtengine::ProcEvent EvICMprimariMethod; @@ -107,6 +109,7 @@ private: rtengine::ProcEvent EvICMpreser; rtengine::ProcEvent EvICMLabGridciexy; rtengine::ProcEvent EvICMfbw; + rtengine::ProcEvent EvICMgamut; LabGrid *labgridcie; IdleRegister idle_register; @@ -121,6 +124,7 @@ private: Gtk::Box* iVBox; Gtk::Box* wTRCBox; Gtk::CheckButton* fbw; + Gtk::CheckButton* gamut; Gtk::CheckButton* obpc; Gtk::RadioButton* inone; @@ -175,6 +179,8 @@ private: float nextwy; public: + static const Glib::ustring TOOL_NAME; + ICMPanel(); ~ICMPanel() override; @@ -196,6 +202,7 @@ public: void aiChanged(int n); void oBPCChanged(); void fbwChanged(); + void gamutChanged(); void ipChanged(); void ipSelectionChanged(); void dcpIlluminantChanged(); diff --git a/rtgui/impulsedenoise.cc b/rtgui/impulsedenoise.cc index cc2e10899..1df662aad 100644 --- a/rtgui/impulsedenoise.cc +++ b/rtgui/impulsedenoise.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -ImpulseDenoise::ImpulseDenoise () : FoldableToolPanel(this, "impulsedenoise", M("TP_IMPULSEDENOISE_LABEL"), true, true) +const Glib::ustring ImpulseDenoise::TOOL_NAME = "impulsedenoise"; + +ImpulseDenoise::ImpulseDenoise () : FoldableToolPanel(this, TOOL_NAME, M("TP_IMPULSEDENOISE_LABEL"), true, true) { thresh = Gtk::manage (new Adjuster (M("TP_IMPULSEDENOISE_THRESH"), 0, 100, 1, 50)); diff --git a/rtgui/impulsedenoise.h b/rtgui/impulsedenoise.h index b8acafcfc..c4c297927 100644 --- a/rtgui/impulsedenoise.h +++ b/rtgui/impulsedenoise.h @@ -34,6 +34,7 @@ protected: //Adjuster* edge; public: + static const Glib::ustring TOOL_NAME; ImpulseDenoise (); diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index d2279f586..e29733cac 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -19,6 +19,7 @@ #include #include "labcurve.h" +#include "eventmapper.h" #include "curveeditor.h" #include "curveeditorgroup.h" @@ -32,61 +33,82 @@ using namespace rtengine; using namespace rtengine::procparams; -LCurve::LCurve () : FoldableToolPanel(this, "labcurves", M("TP_LABCURVE_LABEL"), false, true) +const Glib::ustring LCurve::TOOL_NAME = "labcurves"; + +LCurve::LCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_LABCURVE_LABEL"), false, true) { - brightness = Gtk::manage (new Adjuster (M("TP_LABCURVE_BRIGHTNESS"), -100., 100., 1., 0.)); - contrast = Gtk::manage (new Adjuster (M("TP_LABCURVE_CONTRAST"), -100., 100., 1., 0.)); - chromaticity = Gtk::manage (new Adjuster (M("TP_LABCURVE_CHROMATICITY"), -100., 100., 1., 0.)); + auto m = ProcEventMapper::getInstance(); + Evgamutmunsell = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_GAMUTMUNSEL"); + CurveListener::setMulti(true); + brightness = Gtk::manage(new Adjuster(M("TP_LABCURVE_BRIGHTNESS"), -100., 100., 1., 0.)); + contrast = Gtk::manage(new Adjuster(M("TP_LABCURVE_CONTRAST"), -100., 100., 1., 0.)); + chromaticity = Gtk::manage(new Adjuster(M("TP_LABCURVE_CHROMATICITY"), -100., 100., 1., 0.)); chromaticity->set_tooltip_markup(M("TP_LABCURVE_CHROMA_TOOLTIP")); - pack_start (*brightness); - brightness->show (); + pack_start(*brightness); + brightness->show(); - pack_start (*contrast); - contrast->show (); + pack_start(*contrast); + contrast->show(); - pack_start (*chromaticity); - chromaticity->show (); + pack_start(*chromaticity); + chromaticity->show(); - brightness->setAdjusterListener (this); - contrast->setAdjusterListener (this); - chromaticity->setAdjusterListener (this); + brightness->setAdjusterListener(this); + contrast->setAdjusterListener(this); + chromaticity->setAdjusterListener(this); brightness->setLogScale(2, 0, true); contrast->setLogScale(2, 0, true); chromaticity->setLogScale(2, 0, true); //%%%%%%%%%%%%%%%%%% - Gtk::Separator* hsep2 = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); - hsep2->show (); - pack_start (*hsep2, Gtk::PACK_EXPAND_WIDGET, 4); + Gtk::Separator* hsep2 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); + hsep2->show(); + pack_start(*hsep2, Gtk::PACK_EXPAND_WIDGET, 4); - avoidcolorshift = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_AVOIDCOLORSHIFT"))); - avoidcolorshift->set_tooltip_text (M("TP_LABCURVE_AVOIDCOLORSHIFT_TOOLTIP")); - pack_start (*avoidcolorshift, Gtk::PACK_SHRINK, 4); - lcredsk = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_LCREDSK"))); - lcredsk->set_tooltip_markup (M("TP_LABCURVE_LCREDSK_TOOLTIP")); - pack_start (*lcredsk); - rstprotection = Gtk::manage ( new Adjuster (M("TP_LABCURVE_RSTPROTECTION"), 0., 100., 0.1, 0.) ); - pack_start (*rstprotection); - rstprotection->show (); - rstprotection->setAdjusterListener (this); - rstprotection->set_tooltip_text (M("TP_LABCURVE_RSTPRO_TOOLTIP")); + Gtk::Box* metHBox = Gtk::manage(new Gtk::Box()); + metHBox->set_spacing(2); + Gtk::Label* metLabel = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_AVOID") + ":")); + metHBox->pack_start(*metLabel, Gtk::PACK_SHRINK); - acconn = avoidcolorshift->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::avoidcolorshift_toggled) ); - lcconn = lcredsk->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::lcredsk_toggled) ); + gamutmunselmethod = Gtk::manage(new MyComboBoxText()); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTNON")); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTLABRELA")); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTXYZABSO")); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTXYZRELA")); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTMUNSELL")); + gamutmunselmethod->set_active(4); + gamutmunselmethod->set_tooltip_text(M("TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP")); + metHBox->pack_start(*gamutmunselmethod); + pack_start(*metHBox); + gamutmunselmethodconn = gamutmunselmethod->signal_changed().connect(sigc::mem_fun(*this, &LCurve::gamutmunselChanged)); + + + lcredsk = Gtk::manage(new Gtk::CheckButton(M("TP_LABCURVE_LCREDSK"))); + lcredsk->set_tooltip_markup(M("TP_LABCURVE_LCREDSK_TOOLTIP")); + pack_start(*lcredsk); + + rstprotection = Gtk::manage(new Adjuster(M("TP_LABCURVE_RSTPROTECTION"), 0., 100., 0.1, 0.)); + pack_start(*rstprotection); + rstprotection->show(); + + rstprotection->setAdjusterListener(this); + rstprotection->set_tooltip_text(M("TP_LABCURVE_RSTPRO_TOOLTIP")); + + lcconn = lcredsk->signal_toggled().connect(sigc::mem_fun(*this, &LCurve::lcredsk_toggled)); //%%%%%%%%%%%%%%%%%%% - Gtk::Separator* hsep3 = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); - hsep3->show (); - pack_start (*hsep3, Gtk::PACK_EXPAND_WIDGET, 4); + Gtk::Separator* hsep3 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); + hsep3->show(); + pack_start(*hsep3, Gtk::PACK_EXPAND_WIDGET, 4); - curveEditorG = new CurveEditorGroup (options.lastLabCurvesDir); - curveEditorG->setCurveListener (this); + curveEditorG = new CurveEditorGroup(options.lastLabCurvesDir); + curveEditorG->setCurveListener(this); lshape = static_cast(curveEditorG->addCurve(CT_Diagonal, "L*")); lshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_LL_TOOLTIP")); @@ -216,88 +238,111 @@ LCurve::LCurve () : FoldableToolPanel(this, "labcurves", M("TP_LABCURVE_LABEL"), // This will add the reset button at the end of the curveType buttons curveEditorG->curveListComplete(); - pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); - Gtk::Separator* hsepdh = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); - hsepdh->show (); - pack_start (*hsepdh, Gtk::PACK_EXPAND_WIDGET, 4); + pack_start(*curveEditorG, Gtk::PACK_SHRINK, 4); + Gtk::Separator* hsepdh = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); + hsepdh->show(); + pack_start(*hsepdh, Gtk::PACK_EXPAND_WIDGET, 4); + show_all_children(); } -LCurve::~LCurve () +LCurve::~LCurve() { delete curveEditorG; } -void LCurve::read (const ProcParams* pp, const ParamsEdited* pedited) +void LCurve::read(const ProcParams* pp, const ParamsEdited* pedited) { - disableListener (); + disableListener(); + gamutmunselmethodconn.block(true); + + + brightness->setValue(pp->labCurve.brightness); + contrast->setValue(pp->labCurve.contrast); + chromaticity->setValue(pp->labCurve.chromaticity); + adjusterChanged(chromaticity, pp->labCurve.chromaticity); // To update the GUI sensitiveness + //%%%%%%%%%%%%%%%%%%%%%% + rstprotection->setValue(pp->labCurve.rstprotection); + + + bwtconn.block(true); + lcconn.block(true); + lcredsk->set_active(pp->labCurve.lcredsk); + + bwtconn.block(false); + lcconn.block(false); + + lastLCVal = pp->labCurve.lcredsk; + //%%%%%%%%%%%%%%%%%%%%%% + + lshape->setCurve(pp->labCurve.lcurve); + ashape->setCurve(pp->labCurve.acurve); + bshape->setCurve(pp->labCurve.bcurve); + ccshape->setCurve(pp->labCurve.cccurve); + chshape->setCurve(pp->labCurve.chcurve); + lhshape->setCurve(pp->labCurve.lhcurve); + hhshape->setCurve(pp->labCurve.hhcurve); + lcshape->setCurve(pp->labCurve.lccurve); + clshape->setCurve(pp->labCurve.clcurve); + + if (pedited && !pedited->labCurve.gamutmunselmethod) { + gamutmunselmethod->set_active(4); // "Unchanged" + } else if (pp->labCurve.gamutmunselmethod == "NONE") { + gamutmunselmethod->set_active(0); + } else if (pp->labCurve.gamutmunselmethod == "LAB") { + gamutmunselmethod->set_active(1); + } else if (pp->labCurve.gamutmunselmethod == "XYZ") { + gamutmunselmethod->set_active(2); + } else if (pp->labCurve.gamutmunselmethod == "XYZREL") { + gamutmunselmethod->set_active(3); + } else if (pp->labCurve.gamutmunselmethod == "MUN") { + gamutmunselmethod->set_active(4); + } + + gamutmunselChanged(); if (pedited) { - brightness->setEditedState (pedited->labCurve.brightness ? Edited : UnEdited); - contrast->setEditedState (pedited->labCurve.contrast ? Edited : UnEdited); - chromaticity->setEditedState (pedited->labCurve.chromaticity ? Edited : UnEdited); + brightness->setEditedState(pedited->labCurve.brightness ? Edited : UnEdited); + contrast->setEditedState(pedited->labCurve.contrast ? Edited : UnEdited); + chromaticity->setEditedState(pedited->labCurve.chromaticity ? Edited : UnEdited); //%%%%%%%%%%%%%%%%%%%%%% - rstprotection->setEditedState (pedited->labCurve.rstprotection ? Edited : UnEdited); - avoidcolorshift->set_inconsistent (!pedited->labCurve.avoidcolorshift); - lcredsk->set_inconsistent (!pedited->labCurve.lcredsk); + rstprotection->setEditedState(pedited->labCurve.rstprotection ? Edited : UnEdited); + lcredsk->set_inconsistent(!pedited->labCurve.lcredsk); //%%%%%%%%%%%%%%%%%%%%%% - lshape->setUnChanged (!pedited->labCurve.lcurve); - ashape->setUnChanged (!pedited->labCurve.acurve); - bshape->setUnChanged (!pedited->labCurve.bcurve); - ccshape->setUnChanged (!pedited->labCurve.cccurve); - chshape->setUnChanged (!pedited->labCurve.chcurve); - lhshape->setUnChanged (!pedited->labCurve.lhcurve); - hhshape->setUnChanged (!pedited->labCurve.hhcurve); - lcshape->setUnChanged (!pedited->labCurve.lccurve); - clshape->setUnChanged (!pedited->labCurve.clcurve); + lshape->setUnChanged(!pedited->labCurve.lcurve); + ashape->setUnChanged(!pedited->labCurve.acurve); + bshape->setUnChanged(!pedited->labCurve.bcurve); + ccshape->setUnChanged(!pedited->labCurve.cccurve); + chshape->setUnChanged(!pedited->labCurve.chcurve); + lhshape->setUnChanged(!pedited->labCurve.lhcurve); + hhshape->setUnChanged(!pedited->labCurve.hhcurve); + lcshape->setUnChanged(!pedited->labCurve.lccurve); + clshape->setUnChanged(!pedited->labCurve.clcurve); + + if (!pedited->labCurve.gamutmunselmethod) { + gamutmunselmethod->set_active_text(M("GENERAL_UNCHANGED")); + } set_inconsistent(multiImage && !pedited->labCurve.enabled); } - brightness->setValue (pp->labCurve.brightness); - contrast->setValue (pp->labCurve.contrast); - chromaticity->setValue (pp->labCurve.chromaticity); - adjusterChanged(chromaticity, pp->labCurve.chromaticity); // To update the GUI sensitiveness - //%%%%%%%%%%%%%%%%%%%%%% - rstprotection->setValue (pp->labCurve.rstprotection); + gamutmunselmethodconn.block(false); - bwtconn.block (true); - acconn.block (true); - lcconn.block (true); - avoidcolorshift->set_active (pp->labCurve.avoidcolorshift); - lcredsk->set_active (pp->labCurve.lcredsk); - - bwtconn.block (false); - acconn.block (false); - lcconn.block (false); - - lastACVal = pp->labCurve.avoidcolorshift; - lastLCVal = pp->labCurve.lcredsk; - //%%%%%%%%%%%%%%%%%%%%%% - - lshape->setCurve (pp->labCurve.lcurve); - ashape->setCurve (pp->labCurve.acurve); - bshape->setCurve (pp->labCurve.bcurve); - ccshape->setCurve (pp->labCurve.cccurve); - chshape->setCurve (pp->labCurve.chcurve); - lhshape->setCurve (pp->labCurve.lhcurve); - hhshape->setCurve (pp->labCurve.hhcurve); - lcshape->setCurve (pp->labCurve.lccurve); - clshape->setCurve (pp->labCurve.clcurve); setEnabled(pp->labCurve.enabled); - + queue_draw(); - enableListener (); + enableListener(); } -void LCurve::autoOpenCurve () + +void LCurve::autoOpenCurve() { // Open up the first curve if selected bool active = lshape->openIfNonlinear(); @@ -336,7 +381,7 @@ void LCurve::autoOpenCurve () } -void LCurve::setEditProvider (EditDataProvider *provider) +void LCurve::setEditProvider(EditDataProvider *provider) { lshape->setEditProvider(provider); ccshape->setEditProvider(provider); @@ -351,127 +396,128 @@ void LCurve::setEditProvider (EditDataProvider *provider) } -void LCurve::write (ProcParams* pp, ParamsEdited* pedited) +void LCurve::write(ProcParams* pp, ParamsEdited* pedited) { pp->labCurve.enabled = getEnabled(); - - pp->labCurve.brightness = brightness->getValue (); - pp->labCurve.contrast = (int)contrast->getValue (); - pp->labCurve.chromaticity = (int)chromaticity->getValue (); - //%%%%%%%%%%%%%%%%%%%%%% - pp->labCurve.avoidcolorshift = avoidcolorshift->get_active (); - pp->labCurve.lcredsk = lcredsk->get_active (); - pp->labCurve.rstprotection = rstprotection->getValue (); + pp->labCurve.brightness = brightness->getValue(); + pp->labCurve.contrast = (int)contrast->getValue(); + pp->labCurve.chromaticity = (int)chromaticity->getValue(); + //%%%%%%%%%%%%%%%%%%%%%% + pp->labCurve.lcredsk = lcredsk->get_active(); + + pp->labCurve.rstprotection = rstprotection->getValue(); //%%%%%%%%%%%%%%%%%%%%%% - pp->labCurve.lcurve = lshape->getCurve (); - pp->labCurve.acurve = ashape->getCurve (); - pp->labCurve.bcurve = bshape->getCurve (); - pp->labCurve.cccurve = ccshape->getCurve (); - pp->labCurve.chcurve = chshape->getCurve (); - pp->labCurve.lhcurve = lhshape->getCurve (); - pp->labCurve.hhcurve = hhshape->getCurve (); - pp->labCurve.lccurve = lcshape->getCurve (); - pp->labCurve.clcurve = clshape->getCurve (); + pp->labCurve.lcurve = lshape->getCurve(); + pp->labCurve.acurve = ashape->getCurve(); + pp->labCurve.bcurve = bshape->getCurve(); + pp->labCurve.cccurve = ccshape->getCurve(); + pp->labCurve.chcurve = chshape->getCurve(); + pp->labCurve.lhcurve = lhshape->getCurve(); + pp->labCurve.hhcurve = hhshape->getCurve(); + pp->labCurve.lccurve = lcshape->getCurve(); + pp->labCurve.clcurve = clshape->getCurve(); + + if (pedited) { - pedited->labCurve.brightness = brightness->getEditedState (); - pedited->labCurve.contrast = contrast->getEditedState (); - pedited->labCurve.chromaticity = chromaticity->getEditedState (); + pedited->labCurve.brightness = brightness->getEditedState(); + pedited->labCurve.contrast = contrast->getEditedState(); + pedited->labCurve.chromaticity = chromaticity->getEditedState(); //%%%%%%%%%%%%%%%%%%%%%% - pedited->labCurve.avoidcolorshift = !avoidcolorshift->get_inconsistent(); pedited->labCurve.lcredsk = !lcredsk->get_inconsistent(); - pedited->labCurve.rstprotection = rstprotection->getEditedState (); + pedited->labCurve.rstprotection = rstprotection->getEditedState(); + pedited->labCurve.gamutmunselmethod = gamutmunselmethod->get_active_text() != M("GENERAL_UNCHANGED"); - pedited->labCurve.lcurve = !lshape->isUnChanged (); - pedited->labCurve.acurve = !ashape->isUnChanged (); - pedited->labCurve.bcurve = !bshape->isUnChanged (); - pedited->labCurve.cccurve = !ccshape->isUnChanged (); - pedited->labCurve.chcurve = !chshape->isUnChanged (); - pedited->labCurve.lhcurve = !lhshape->isUnChanged (); - pedited->labCurve.hhcurve = !hhshape->isUnChanged (); - pedited->labCurve.lccurve = !lcshape->isUnChanged (); - pedited->labCurve.clcurve = !clshape->isUnChanged (); + pedited->labCurve.lcurve = !lshape->isUnChanged(); + pedited->labCurve.acurve = !ashape->isUnChanged(); + pedited->labCurve.bcurve = !bshape->isUnChanged(); + pedited->labCurve.cccurve = !ccshape->isUnChanged(); + pedited->labCurve.chcurve = !chshape->isUnChanged(); + pedited->labCurve.lhcurve = !lhshape->isUnChanged(); + pedited->labCurve.hhcurve = !hhshape->isUnChanged(); + pedited->labCurve.lccurve = !lcshape->isUnChanged(); + pedited->labCurve.clcurve = !clshape->isUnChanged(); pedited->labCurve.enabled = !get_inconsistent(); + } + if (gamutmunselmethod->get_active_row_number() == 0) { + pp->labCurve.gamutmunselmethod = "NONE"; + } else if (gamutmunselmethod->get_active_row_number() == 1) { + pp->labCurve.gamutmunselmethod = "LAB"; + } else if (gamutmunselmethod->get_active_row_number() == 2) { + pp->labCurve.gamutmunselmethod = "XYZ"; + } else if (gamutmunselmethod->get_active_row_number() == 3) { + pp->labCurve.gamutmunselmethod = "XYZREL"; + } else if (gamutmunselmethod->get_active_row_number() == 4) { + pp->labCurve.gamutmunselmethod = "MUN"; + } + + + } -void LCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) +void LCurve::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) { - brightness->setDefault (defParams->labCurve.brightness); - contrast->setDefault (defParams->labCurve.contrast); - chromaticity->setDefault (defParams->labCurve.chromaticity); - rstprotection->setDefault (defParams->labCurve.rstprotection); + brightness->setDefault(defParams->labCurve.brightness); + contrast->setDefault(defParams->labCurve.contrast); + chromaticity->setDefault(defParams->labCurve.chromaticity); + rstprotection->setDefault(defParams->labCurve.rstprotection); if (pedited) { - brightness->setDefaultEditedState (pedited->labCurve.brightness ? Edited : UnEdited); - contrast->setDefaultEditedState (pedited->labCurve.contrast ? Edited : UnEdited); - chromaticity->setDefaultEditedState (pedited->labCurve.chromaticity ? Edited : UnEdited); - rstprotection->setDefaultEditedState (pedited->labCurve.rstprotection ? Edited : UnEdited); + brightness->setDefaultEditedState(pedited->labCurve.brightness ? Edited : UnEdited); + contrast->setDefaultEditedState(pedited->labCurve.contrast ? Edited : UnEdited); + chromaticity->setDefaultEditedState(pedited->labCurve.chromaticity ? Edited : UnEdited); + rstprotection->setDefaultEditedState(pedited->labCurve.rstprotection ? Edited : UnEdited); } else { - brightness->setDefaultEditedState (Irrelevant); - contrast->setDefaultEditedState (Irrelevant); - chromaticity->setDefaultEditedState (Irrelevant); - rstprotection->setDefaultEditedState (Irrelevant); + brightness->setDefaultEditedState(Irrelevant); + contrast->setDefaultEditedState(Irrelevant); + chromaticity->setDefaultEditedState(Irrelevant); + rstprotection->setDefaultEditedState(Irrelevant); } } //%%%%%%%%%%%%%%%%%%%%%% -//Color shift control changed -void LCurve::avoidcolorshift_toggled () + +void LCurve::gamutmunselChanged() { - if (batchMode) { - if (avoidcolorshift->get_inconsistent()) { - avoidcolorshift->set_inconsistent (false); - acconn.block (true); - avoidcolorshift->set_active (false); - acconn.block (false); - } else if (lastACVal) { - avoidcolorshift->set_inconsistent (true); - } - - lastACVal = avoidcolorshift->get_active (); + if (listener && (multiImage || getEnabled())) { + listener->panelChanged(Evgamutmunsell, gamutmunselmethod->get_active_text()); } - if (listener && getEnabled()) { - if (avoidcolorshift->get_active ()) { - listener->panelChanged (EvLAvoidColorShift, M("GENERAL_ENABLED")); - } else { - listener->panelChanged (EvLAvoidColorShift, M("GENERAL_DISABLED")); - } - } } -void LCurve::lcredsk_toggled () + +void LCurve::lcredsk_toggled() { if (batchMode) { if (lcredsk->get_inconsistent()) { - lcredsk->set_inconsistent (false); - lcconn.block (true); - lcredsk->set_active (false); - lcconn.block (false); + lcredsk->set_inconsistent(false); + lcconn.block(true); + lcredsk->set_active(false); + lcconn.block(false); } else if (lastLCVal) { - lcredsk->set_inconsistent (true); + lcredsk->set_inconsistent(true); } - lastLCVal = lcredsk->get_active (); + lastLCVal = lcredsk->get_active(); } else { lcshape->refresh(); } if (listener && getEnabled()) { - if (lcredsk->get_active ()) { - listener->panelChanged (EvLLCredsk, M("GENERAL_ENABLED")); + if (lcredsk->get_active()) { + listener->panelChanged(EvLLCredsk, M("GENERAL_ENABLED")); } else { - listener->panelChanged (EvLLCredsk, M("GENERAL_DISABLED")); + listener->panelChanged(EvLLCredsk, M("GENERAL_DISABLED")); } } } @@ -484,44 +530,44 @@ void LCurve::lcredsk_toggled () * If more than one curve has been added, the curve listener is automatically * set to 'multi=true', and send a pointer of the modified curve in a parameter */ -void LCurve::curveChanged (CurveEditor* ce) +void LCurve::curveChanged(CurveEditor* ce) { if (listener && getEnabled()) { if (ce == lshape) { - listener->panelChanged (EvLLCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLLCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == ashape) { - listener->panelChanged (EvLaCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLaCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == bshape) { - listener->panelChanged (EvLbCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLbCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == ccshape) { - listener->panelChanged (EvLCCCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLCCCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == chshape) { - listener->panelChanged (EvLCHCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLCHCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == lhshape) { - listener->panelChanged (EvLLHCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLLHCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == hhshape) { - listener->panelChanged (EvLHHCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLHHCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == lcshape) { - listener->panelChanged (EvLLCCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLLCCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == clshape) { - listener->panelChanged (EvLCLCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLCLCurve, M("HISTORY_CUSTOMCURVE")); } @@ -533,45 +579,43 @@ void LCurve::adjusterChanged(Adjuster* a, double newval) Glib::ustring costr; if (a == brightness) { - costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), a->getValue()); + costr = Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), a->getValue()); } else if (a == rstprotection) { - costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(1), a->getValue()); + costr = Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(1), a->getValue()); } else { - costr = Glib::ustring::format ((int)a->getValue()); + costr = Glib::ustring::format((int)a->getValue()); } if (a == brightness) { if (listener && getEnabled()) { - listener->panelChanged (EvLBrightness, costr); + listener->panelChanged(EvLBrightness, costr); } } else if (a == contrast) { if (listener && getEnabled()) { - listener->panelChanged (EvLContrast, costr); + listener->panelChanged(EvLContrast, costr); } } else if (a == rstprotection) { if (listener && getEnabled()) { - listener->panelChanged (EvLRSTProtection, costr); + listener->panelChanged(EvLRSTProtection, costr); } } else if (a == chromaticity) { if (multiImage) { //if chromaticity==-100 (lowest value), we enter the B&W mode and avoid color shift and rstprotection has no effect - rstprotection->set_sensitive( true ); - avoidcolorshift->set_sensitive( true ); - lcredsk->set_sensitive( true ); + rstprotection->set_sensitive(true); + lcredsk->set_sensitive(true); } else { //if chromaticity==-100 (lowest value), we enter the B&W mode and avoid color shift and rstprotection has no effect - rstprotection->set_sensitive( int(newval) > -100 ); //no reason for grey rstprotection - avoidcolorshift->set_sensitive( int(newval) > -100 ); - lcredsk->set_sensitive( int(newval) > -100 ); + rstprotection->set_sensitive(int(newval) > -100); //no reason for grey rstprotection + lcredsk->set_sensitive(int(newval) > -100); } if (listener && getEnabled()) { - listener->panelChanged (EvLSaturation, costr); + listener->panelChanged(EvLSaturation, costr); } } } -void LCurve::colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) +void LCurve::colorForValue(double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) { float R = 0.f, G = 0.f, B = 0.f; @@ -586,47 +630,54 @@ void LCurve::colorForValue (double valX, double valY, enum ColorCaller::ElemType 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*0.8), float(valX), value, R, G, B); + Color::hsv2rgb01(float(valY * 0.8), float(valX), value, R, G, B); } else if (callerId == 6) { // cc - left bar float value = (1.f - 0.7f) * float(valX) + 0.7f; float hue = (1.14056f - 0.92f) * float(valY) + 0.92f; + if (hue > 1.0f) { hue -= 1.0f; } + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) Color::hsv2rgb01(hue, float(valX), value, R, G, B); } else if (callerId == 3) { // lc - bottom bar float value = (1.f - 0.7f) * float(valX) + 0.7f; + if (lcredsk->get_active()) { // skin range // -0.1 rad < Hue < 1.6 rad // Y axis / from 0.92 up to 0.14056 float hue = (1.14056f - 0.92f) * float(valY) + 0.92f; + if (hue > 1.0f) { hue -= 1.0f; } + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) Color::hsv2rgb01(hue, float(valX), value, R, G, B); } else { // whole hue range // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) - Color::hsv2rgb01(float(valY*0.8), float(valX), value, R, G, B); + Color::hsv2rgb01(float(valY * 0.8), float(valX), value, R, G, B); } } else if (callerId == 4) { // LH - bottom bar Color::hsv2rgb01(float(valX), 0.5f, float(valY), R, G, B); } else if (callerId == 5) { // HH - bottom bar float h = float((valY - 0.5) * 0.3 + valX); + if (h > 1.0f) { h -= 1.0f; } else if (h < 0.0f) { h += 1.0f; } + Color::hsv2rgb01(h, 0.5f, 0.5f, R, G, B); } else if (callerId == 7) { // cc and cl - left bar 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*0.8), 1.f - float(valX), value, R, G, B); + Color::hsv2rgb01(float(valY * 0.8), 1.f - float(valX), value, R, G, B); } caller->ccRed = double(R); @@ -634,17 +685,19 @@ void LCurve::colorForValue (double valX, double valY, enum ColorCaller::ElemType caller->ccBlue = double(B); } -void LCurve::setBatchMode (bool batchMode) +void LCurve::setBatchMode(bool batchMode) { - ToolPanel::setBatchMode (batchMode); - brightness->showEditedCB (); - contrast->showEditedCB (); - chromaticity->showEditedCB (); - rstprotection->showEditedCB (); - curveEditorG->setBatchMode (batchMode); + ToolPanel::setBatchMode(batchMode); + brightness->showEditedCB(); + contrast->showEditedCB(); + chromaticity->showEditedCB(); + rstprotection->showEditedCB(); + curveEditorG->setBatchMode(batchMode); lcshape->setBottomBarColorProvider(nullptr, -1); lcshape->setLeftBarColorProvider(nullptr, -1); + gamutmunselmethod->append(M("GENERAL_UNCHANGED")); + } @@ -661,13 +714,13 @@ void LCurve::updateCurveBackgroundHistogram( const LUTu& histLRETI ) { - lshape->updateBackgroundHistogram (histLCurve); - ccshape->updateBackgroundHistogram (histCCurve); - lcshape->updateBackgroundHistogram (histCCurve); - clshape->updateBackgroundHistogram (histLCurve); + lshape->updateBackgroundHistogram(histLCurve); + ccshape->updateBackgroundHistogram(histCCurve); + lcshape->updateBackgroundHistogram(histCCurve); + clshape->updateBackgroundHistogram(histLCurve); } -void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) +void LCurve::setAdjusterBehavior(bool bradd, bool contradd, bool satadd) { brightness->setAddMode(bradd); @@ -675,7 +728,7 @@ void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) chromaticity->setAddMode(satadd); } -void LCurve::trimValues (rtengine::procparams::ProcParams* pp) +void LCurve::trimValues(rtengine::procparams::ProcParams* pp) { brightness->trimValue(pp->labCurve.brightness); @@ -687,11 +740,11 @@ void LCurve::enabledChanged() { if (listener) { if (get_inconsistent()) { - listener->panelChanged (EvLEnabled, M("GENERAL_UNCHANGED")); + listener->panelChanged(EvLEnabled, M("GENERAL_UNCHANGED")); } else if (getEnabled()) { - listener->panelChanged (EvLEnabled, M("GENERAL_ENABLED")); + listener->panelChanged(EvLEnabled, M("GENERAL_ENABLED")); } else { - listener->panelChanged (EvLEnabled, M("GENERAL_DISABLED")); + listener->panelChanged(EvLEnabled, M("GENERAL_DISABLED")); } } } diff --git a/rtgui/labcurve.h b/rtgui/labcurve.h index dfb79ae7a..99e0cf0c4 100644 --- a/rtgui/labcurve.h +++ b/rtgui/labcurve.h @@ -59,16 +59,20 @@ protected: DiagonalCurveEditor* cdshape; //%%%%%%%%%%%%%%%% - Gtk::CheckButton* avoidcolorshift; Gtk::CheckButton* lcredsk; + MyComboBoxText* gamutmunselmethod; + sigc::connection gamutmunselmethodconn; + rtengine::ProcEvent Evgamutmunsell; + Adjuster* rstprotection; - sigc::connection bwtconn, acconn, lcconn; + sigc::connection bwtconn, lcconn; bool lastACVal, lastLCVal; //%%%%%%%%%%%%%%%% public: + static const Glib::ustring TOOL_NAME; LCurve (); ~LCurve () override; @@ -84,8 +88,8 @@ public: void curveChanged (CurveEditor* ce) override; void adjusterChanged (Adjuster* a, double newval) override; - void avoidcolorshift_toggled (); void lcredsk_toggled(); + void gamutmunselChanged(); void updateCurveBackgroundHistogram( const LUTu& histToneCurve, diff --git a/rtgui/lensgeom.cc b/rtgui/lensgeom.cc index 621f9c278..0064ecee3 100644 --- a/rtgui/lensgeom.cc +++ b/rtgui/lensgeom.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -LensGeometry::LensGeometry () : FoldableToolPanel(this, "lensgeom", M("TP_LENSGEOM_LABEL")), rlistener(nullptr), lastFill(false) +const Glib::ustring LensGeometry::TOOL_NAME = "lensgeom"; + +LensGeometry::LensGeometry () : FoldableToolPanel(this, TOOL_NAME, M("TP_LENSGEOM_LABEL")), rlistener(nullptr), lastFill(false) { auto m = ProcEventMapper::getInstance(); @@ -50,9 +52,6 @@ LensGeometry::LensGeometry () : FoldableToolPanel(this, "lensgeom", M("TP_LENSGE autoCrop->get_style_context()->add_class("independent"); pack_start (*autoCrop, Gtk::PACK_SHRINK, 2); - packBox = Gtk::manage (new ToolParamBlock ()); - pack_start (*packBox); - method->connect(method->signal_changed().connect(sigc::mem_fun(*this, &LensGeometry::methodChanged))); autoCrop->signal_pressed().connect(sigc::mem_fun(*this, &LensGeometry::autoCropPressed)); fillConn = fill->signal_toggled().connect(sigc::mem_fun(*this, &LensGeometry::fillPressed)); diff --git a/rtgui/lensgeom.h b/rtgui/lensgeom.h index 73c28b006..fa260e177 100644 --- a/rtgui/lensgeom.h +++ b/rtgui/lensgeom.h @@ -35,19 +35,14 @@ protected: Gtk::CheckButton* fill; bool lastFill; sigc::connection fillConn; - ToolParamBlock* packBox; rtengine::ProcEvent EvTransMethod; public: + static const Glib::ustring TOOL_NAME; LensGeometry (); ~LensGeometry () override; - Gtk::Box* getPackBox () - { - return packBox; - } - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; void setBatchMode (bool batchMode) override; diff --git a/rtgui/lensprofile.cc b/rtgui/lensprofile.cc index e33fd314c..a713c0164 100644 --- a/rtgui/lensprofile.cc +++ b/rtgui/lensprofile.cc @@ -36,8 +36,10 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring LensProfilePanel::TOOL_NAME = "lensprof"; + LensProfilePanel::LensProfilePanel() : - FoldableToolPanel(this, "lensprof", M("TP_LENSPROFILE_LABEL")), + FoldableToolPanel(this, TOOL_NAME, M("TP_LENSPROFILE_LABEL")), lcModeChanged(false), lcpFileChanged(false), useDistChanged(false), diff --git a/rtgui/lensprofile.h b/rtgui/lensprofile.h index 7b5b7343c..42746f41e 100644 --- a/rtgui/lensprofile.h +++ b/rtgui/lensprofile.h @@ -28,6 +28,8 @@ class LensProfilePanel final : public FoldableToolPanel { public: + static const Glib::ustring TOOL_NAME; + LensProfilePanel(); void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; diff --git a/rtgui/localcontrast.cc b/rtgui/localcontrast.cc index 6b668a1eb..a56f9cb15 100644 --- a/rtgui/localcontrast.cc +++ b/rtgui/localcontrast.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -LocalContrast::LocalContrast(): FoldableToolPanel(this, "localcontrast", M("TP_LOCALCONTRAST_LABEL"), false, true) +const Glib::ustring LocalContrast::TOOL_NAME = "localcontrast"; + +LocalContrast::LocalContrast(): FoldableToolPanel(this, TOOL_NAME, M("TP_LOCALCONTRAST_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); /* EvLocalContrastEnabled = m->newEvent(RGBCURVE, "HISTORY_MSG_LOCALCONTRAST_ENABLED"); diff --git a/rtgui/localcontrast.h b/rtgui/localcontrast.h index d1d25fb3d..fa769c35e 100644 --- a/rtgui/localcontrast.h +++ b/rtgui/localcontrast.h @@ -38,6 +38,7 @@ private: rtengine::ProcEvent EvLocalContrastLightness; public: + static const Glib::ustring TOOL_NAME; LocalContrast(); diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index 4fb61c1c6..8e8e999d3 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -29,6 +29,8 @@ using namespace procparams; extern Options options; +const Glib::ustring Locallab::TOOL_NAME = "locallab"; + /* ==== LocallabToolList ==== */ LocallabToolList::LocallabToolList(): // Tool list GUI elements @@ -142,7 +144,7 @@ void LocallabToolList::toolRowSelected() /* ==== Locallab ==== */ Locallab::Locallab(): - FoldableToolPanel(this, "locallab", M("TP_LOCALLAB_LABEL"), false, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_LOCALLAB_LABEL"), false, true), // Spot control panel widget expsettings(Gtk::manage(new ControlSpotPanel())), @@ -277,6 +279,18 @@ void Locallab::read(const rtengine::procparams::ProcParams* pp, const ParamsEdit } else { r->shapeMethod = 3; } + + if (pp->locallab.spots.at(i).avoidgamutMethod == "NONE") { + r->avoidgamutMethod = 0; + } else if (pp->locallab.spots.at(i).avoidgamutMethod == "LAB") { + r->avoidgamutMethod = 1; + } else if (pp->locallab.spots.at(i).avoidgamutMethod == "XYZ") { + r->avoidgamutMethod= 2; + } else if (pp->locallab.spots.at(i).avoidgamutMethod == "XYZREL") { + r->avoidgamutMethod= 3; + } else if (pp->locallab.spots.at(i).avoidgamutMethod == "MUNS") { + r->avoidgamutMethod= 4; + } r->locX = pp->locallab.spots.at(i).loc.at(0); r->locXL = pp->locallab.spots.at(i).loc.at(1); @@ -306,8 +320,6 @@ void Locallab::read(const rtengine::procparams::ProcParams* pp, const ParamsEdit r->avoidrad = pp->locallab.spots.at(i).avoidrad; 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->avoidmun = pp->locallab.spots.at(i).avoidmun; 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; @@ -441,6 +453,18 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r->shapeMethod = 3; } + if (newSpot->avoidgamutMethod == "NONE") { + r->avoidgamutMethod = 0; + } else if (newSpot->avoidgamutMethod == "LAB") { + r->avoidgamutMethod = 1; + } else if (newSpot->avoidgamutMethod == "XYZ") { + r->avoidgamutMethod = 2; + } else if (newSpot->avoidgamutMethod == "XYZREL") { + r->avoidgamutMethod = 3; + } else if (newSpot->avoidgamutMethod == "MUNS") { + r->avoidgamutMethod = 4; + } + // Calculate spot size and center position according to preview area if (provider && !batchMode) { provider->getImageSize(imW, imH); @@ -488,8 +512,6 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r->avoidrad = newSpot->avoidrad; r->hishow = newSpot->hishow; r->activ = newSpot->activ; - r->avoid = newSpot->avoid; - r->avoidmun = newSpot->avoidmun; r->blwh = newSpot->blwh; r->recurs = newSpot->recurs; r->laplac = newSpot->laplac; @@ -742,6 +764,18 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r->shapeMethod = 3; } //printf("n0=%f n1=%f n2=%f n3=%f\n", (double) newSpot->loc.at(0), (double) newSpot->loc.at(1), (double) newSpot->loc.at(2), (double) newSpot->loc.at(3)); + if (newSpot->avoidgamutMethod == "NONE") { + r->avoidgamutMethod = 0; + } else if (newSpot->avoidgamutMethod == "LAB") { + r->avoidgamutMethod = 1; + } else if (newSpot->avoidgamutMethod== "XYZ") { + r->avoidgamutMethod = 2; + } else if (newSpot->avoidgamutMethod== "XYZREL") { + r->avoidgamutMethod = 3; + } else if (newSpot->avoidgamutMethod== "MUNS") { + r->avoidgamutMethod = 4; + } + //printf("n0=%f n1=%f n2=%f n3=%f\n", (double) newSpot->loc.at(0), (double) newSpot->loc.at(1), (double) newSpot->loc.at(2), (double) newSpot->loc.at(3)); // Calculate spot size and center position according to preview area if (provider && !batchMode) { @@ -799,8 +833,6 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r->colorscope = newSpot->colorscope; r->avoidrad = newSpot->avoidrad; r->activ = newSpot->activ; - r->avoid = newSpot->avoid; - r->avoidmun = newSpot->avoidmun; r->blwh = newSpot->blwh; r->recurs = newSpot->recurs; r->laplac = newSpot->laplac; @@ -927,6 +959,18 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited pp->locallab.spots.at(pp->locallab.selspot).shapeMethod = "SYMSL"; } + if (r->avoidgamutMethod == 0) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "NONE"; + } else if (r->avoidgamutMethod == 1) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "LAB"; + } else if (r->avoidgamutMethod == 2) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "XYZ"; + } else if (r->avoidgamutMethod == 3) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "XYZREL"; + } else if (r->avoidgamutMethod == 4) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "MUNS"; + } + 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; @@ -955,8 +999,6 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited pp->locallab.spots.at(pp->locallab.selspot).avoidrad = r->avoidrad; 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).avoidmun = r->avoidmun; 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; diff --git a/rtgui/locallab.h b/rtgui/locallab.h index 60c186c55..b0030bbe6 100644 --- a/rtgui/locallab.h +++ b/rtgui/locallab.h @@ -132,6 +132,8 @@ private: Glib::ustring spotName; public: + static const Glib::ustring TOOL_NAME; + Locallab(); // FoldableToolPanel management functions diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index feef93564..cebced274 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -148,12 +148,14 @@ int main (int argc, char **argv) } options.rtSettings.lensfunDbDirectory = LENSFUN_DB_PATH; + options.rtSettings.lensfunDbBundleDirectory = LENSFUN_DB_PATH; #else argv0 = DATA_SEARCH_PATH; creditsPath = CREDITS_SEARCH_PATH; licensePath = LICENCE_SEARCH_PATH; options.rtSettings.lensfunDbDirectory = LENSFUN_DB_PATH; + options.rtSettings.lensfunDbBundleDirectory = LENSFUN_DB_PATH; #endif bool quickstart = dontLoadCache (argc, argv); @@ -741,7 +743,7 @@ int processLineParams ( int argc, char **argv ) if (options.defProfRaw == DEFPROFILE_DYNAMIC) { rawParams->deleteInstance(); delete rawParams; - rawParams = ProfileStore::getInstance()->loadDynamicProfile (ii->getMetaData()); + rawParams = ProfileStore::getInstance()->loadDynamicProfile (ii->getMetaData(), inputFile); } std::cout << " Merging default raw processing profile." << std::endl; @@ -750,7 +752,7 @@ int processLineParams ( int argc, char **argv ) if (options.defProfImg == DEFPROFILE_DYNAMIC) { imgParams->deleteInstance(); delete imgParams; - imgParams = ProfileStore::getInstance()->loadDynamicProfile (ii->getMetaData()); + imgParams = ProfileStore::getInstance()->loadDynamicProfile (ii->getMetaData(), inputFile); } std::cout << " Merging default non-raw processing profile." << std::endl; diff --git a/rtgui/main.cc b/rtgui/main.cc index 2ca0d9c91..a2699e758 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -424,12 +424,14 @@ int main (int argc, char **argv) } options.rtSettings.lensfunDbDirectory = LENSFUN_DB_PATH; + options.rtSettings.lensfunDbBundleDirectory = LENSFUN_DB_PATH; #else argv0 = DATA_SEARCH_PATH; creditsPath = CREDITS_SEARCH_PATH; licensePath = LICENCE_SEARCH_PATH; options.rtSettings.lensfunDbDirectory = LENSFUN_DB_PATH; + options.rtSettings.lensfunDbBundleDirectory = LENSFUN_DB_PATH; #endif #ifdef WIN32 diff --git a/rtgui/options.cc b/rtgui/options.cc index a1cc88c03..e230dcf8a 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -313,6 +313,7 @@ void Options::setDefaults() saveFormat.tiffBits = 16; saveFormat.tiffFloat = false; saveFormat.tiffUncompressed = true; + saveFormat.bigTiff = false; saveFormat.saveParams = true; saveFormatBatch.format = "jpg"; @@ -412,6 +413,8 @@ void Options::setDefaults() gimpDir = ""; psDir = ""; customEditorProg = ""; + externalEditors.clear(); + externalEditorIndex = -1; CPBKeys = CPBKT_TID; editorToSendTo = 1; editor_out_dir = EDITOR_OUT_DIR_TEMP; @@ -424,6 +427,7 @@ void Options::setDefaults() //crvOpen.clear (); parseExtensions.clear(); favorites.clear(); + cloneFavoriteTools = false; parseExtensionsEnabled.clear(); parsedExtensions.clear(); parsedExtensionsSet.clear(); @@ -591,6 +595,7 @@ void Options::setDefaults() rtSettings.monitorIntent = rtengine::RI_RELATIVE; rtSettings.monitorBPC = true; rtSettings.autocielab = false; + rtSettings.observer10 = false; rtSettings.autoMonitorProfile = false; rtSettings.adobe = "RTv2_Medium"; // put the name of yours profiles (here windows) rtSettings.prophoto = "RTv2_Large"; // these names appear in the menu "output profile" @@ -620,14 +625,15 @@ void Options::setDefaults() rtSettings.fftwsigma = true; //choice between sigma^2 or empirical formula rtSettings.itcwb_thres = 34;//between 10 to 55 - rtSettings.itcwb_sort = false; + rtSettings.itcwb_sorted = true; rtSettings.itcwb_greenrange = 0;//between 0 to 2 rtSettings.itcwb_greendeltatemp = 2;//between 0 and 4 rtSettings.itcwb_forceextra = true; rtSettings.itcwb_sizereference = 3;//between 1 and 5 rtSettings.itcwb_delta = 1;//between 0 and 5 rtSettings.itcwb_stdobserver10 = true; - rtSettings.itcwb_precis = 5;//3 or 5 or 9 + rtSettings.itcwb_precis = 3;//3 or 5 or 9 + rtSettings.itcwb_nopurple = true; // end locallab //wavelet @@ -685,6 +691,8 @@ void Options::setDefaults() lastICCProfCreatorDir = ""; gimpPluginShowInfoDialog = true; maxRecentFolders = 15; + sortMethod = SORT_BY_NAME; + sortDescending = false; rtSettings.lensfunDbDirectory = ""; // set also in main.cc and main-cli.cc cropGuides = CROP_GUIDE_FULL; cropAutoFit = false; @@ -819,6 +827,7 @@ void Options::readFromFile(Glib::ustring fname) } } + // TODO: Remove. if (keyFile.has_group("External Editor")) { if (keyFile.has_key("External Editor", "EditorKind")) { editorToSendTo = keyFile.get_integer("External Editor", "EditorKind"); @@ -859,6 +868,156 @@ void Options::readFromFile(Glib::ustring fname) } + if (keyFile.has_group("External Editor")) { + if (keyFile.has_key("External Editor", "Names") + || keyFile.has_key("External Editor", "Commands") + || keyFile.has_key("External Editor", "IconsSerialized")) { + // Multiple external editors. + + const auto & names = + !keyFile.has_key("External Editor", "Names") ? + std::vector() : + static_cast>( + keyFile.get_string_list("External Editor", "Names")); + const auto & commands = + !keyFile.has_key("External Editor", "Commands") ? + std::vector() : + static_cast>( + keyFile.get_string_list("External Editor", "Commands")); + const auto & icons_serialized = + !keyFile.has_key("External Editor", "IconsSerialized") ? + std::vector() : + static_cast>( + keyFile.get_string_list("External Editor", "IconsSerialized")); + externalEditors = std::vector(std::max(std::max( + names.size(), commands.size()), icons_serialized.size())); + for (unsigned i = 0; i < names.size(); i++) { + externalEditors[i].name = names[i]; + } + for (unsigned i = 0; i < commands.size(); i++) { + externalEditors[i].command = commands[i]; + } + for (unsigned i = 0; i < icons_serialized.size(); i++) { + externalEditors[i].icon_serialized = icons_serialized[i]; + } + + if (keyFile.has_key("External Editor", "EditorIndex")) { + int index = keyFile.get_integer("External Editor", "EditorIndex"); + externalEditorIndex = std::min( + std::max(-1, index), + static_cast(externalEditors.size()) + ); + } + } else if (keyFile.has_key("External Editor", "EditorKind")) { + // Legacy fixed external editors. Convert to flexible. + + // GIMP == 1, Photoshop == 2, Custom == 3. + editorToSendTo = keyFile.get_integer("External Editor", "EditorKind"); + +#ifdef WIN32 + auto getIconSerialized = [](const Glib::ustring &executable) { + // Backslashes and quotes must be escaped in the text representation of GVariant strings. + // See https://www.freedesktop.org/software/gstreamer-sdk/data/docs/2012.5/glib/gvariant-text.html#gvariant-text-strings + Glib::ustring exec_escaped = ""; + for (const auto character : executable) { + if (character == '\\' || character == '\'') { + exec_escaped += '\\'; + } + exec_escaped += character; + } + return Glib::ustring::compose("('themed', <['%1,0', '%1,0-symbolic']>)", exec_escaped); + }; + Glib::ustring gimpDir = ""; + if (keyFile.has_key("External Editor", "GimpDir")) { + gimpDir = keyFile.get_string("External Editor", "GimpDir"); + } + auto executable = Glib::build_filename(options.gimpDir, "bin", "gimp-win-remote"); + if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) { + if (editorToSendTo == 1) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", getIconSerialized(executable))); + } else { + for (auto ver = 12; ver >= 0; --ver) { + executable = Glib::build_filename(gimpDir, "bin", Glib::ustring::compose(Glib::ustring("gimp-2.%1.exe"), ver)); + if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) { + if (editorToSendTo == 1) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", getIconSerialized(executable))); + break; + } + } + } + + Glib::ustring psDir = ""; + if (keyFile.has_key("External Editor", "PhotoshopDir")) { + psDir = keyFile.get_string("External Editor", "PhotoshopDir"); + } + executable = Glib::build_filename(psDir, "Photoshop.exe"); + if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) { + if (editorToSendTo == 2) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("Photoshop", "\"" + executable + "\"", getIconSerialized(executable))); + } + + if (keyFile.has_key("External Editor", "CustomEditor")) { + executable = keyFile.get_string("External Editor", "CustomEditor"); + if (!executable.empty()) { + if (editorToSendTo == 3) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("-", "\"" + executable + "\"", "")); + } + } +#elif defined __APPLE__ + if (editorToSendTo == 1) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("GIMP", "open -a GIMP", "gimp")); + externalEditors.push_back(ExternalEditor("GIMP-dev", "open -a GIMP-dev", "gimp")); + + if (editorToSendTo == 2) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("Photoshop", "open -a Photoshop", "")); + + if (keyFile.has_key("External Editor", "CustomEditor")) { + auto executable = keyFile.get_string("External Editor", "CustomEditor"); + if (!executable.empty()) { + if (editorToSendTo == 3) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("-", executable, "")); + } + } +#else + if (Glib::find_program_in_path("gimp").compare("")) { + if (editorToSendTo == 1) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("GIMP", "gimp", "gimp")); + } else if (Glib::find_program_in_path("gimp-remote").compare("")) { + if (editorToSendTo == 1) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("GIMP", "gimp-remote", "gimp")); + } + + if (keyFile.has_key("External Editor", "CustomEditor")) { + auto executable = keyFile.get_string("External Editor", "CustomEditor"); + if (!executable.empty()) { + if (editorToSendTo == 3) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("-", executable, "")); + } + } +#endif + } + } + if (keyFile.has_group("Output")) { if (keyFile.has_key("Output", "Format")) { saveFormat.format = keyFile.get_string("Output", "Format"); @@ -888,6 +1047,10 @@ void Options::readFromFile(Glib::ustring fname) saveFormat.tiffUncompressed = keyFile.get_boolean("Output", "TiffUncompressed"); } + if (keyFile.has_key("Output", "BigTiff")) { + saveFormat.bigTiff = keyFile.get_boolean("Output", "BigTiff"); + } + if (keyFile.has_key("Output", "SaveProcParams")) { saveFormat.saveParams = keyFile.get_boolean("Output", "SaveProcParams"); } @@ -1150,6 +1313,19 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("File Browser", "RecentFolders")) { recentFolders = keyFile.get_string_list("File Browser", "RecentFolders"); } + + if (keyFile.has_key("File Browser", "SortMethod")) { + int v = keyFile.get_integer("File Browser", "SortMethod"); + if (v < int(0) || v >= int(SORT_METHOD_COUNT)) { + sortMethod = SORT_BY_NAME; + } else { + sortMethod = SortMethod(v); + } + } + + if (keyFile.has_key("File Browser", "SortDescending")) { + sortDescending = keyFile.get_boolean("File Browser", "SortDescending"); + } } if (keyFile.has_group("Clipping Indication")) { @@ -1225,6 +1401,10 @@ void Options::readFromFile(Glib::ustring fname) favorites = keyFile.get_string_list("GUI", "Favorites"); } + if (keyFile.has_key("GUI", "FavoritesCloneTools")) { + cloneFavoriteTools = keyFile.get_boolean("GUI", "FavoritesCloneTools"); + } + if (keyFile.has_key("GUI", "WindowWidth")) { windowWidth = keyFile.get_integer("GUI", "WindowWidth"); } @@ -1587,6 +1767,10 @@ void Options::readFromFile(Glib::ustring fname) rtSettings.autocielab = keyFile.get_boolean("Color Management", "Autocielab"); } + if (keyFile.has_key("Color Management", "Observer10")) { + rtSettings.observer10 = keyFile.get_boolean("Color Management", "Observer10"); + } + if (keyFile.has_key("Color Management", "CRI")) { rtSettings.CRI_color = keyFile.get_integer("Color Management", "CRI"); } @@ -1622,14 +1806,18 @@ void Options::readFromFile(Glib::ustring fname) rtSettings.itcwb_thres = keyFile.get_integer("Color Management", "Itcwb_thres"); } - if (keyFile.has_key("Color Management", "Itcwb_sort")) { - rtSettings.itcwb_sort = keyFile.get_boolean("Color Management", "Itcwb_sort"); + if (keyFile.has_key("Color Management", "Itcwb_sorted")) { + rtSettings.itcwb_sorted = keyFile.get_boolean("Color Management", "Itcwb_sorted"); } if (keyFile.has_key("Color Management", "Itcwb_forceextra")) { rtSettings.itcwb_forceextra = keyFile.get_boolean("Color Management", "Itcwb_forceextra"); } + if (keyFile.has_key("Color Management", "Itcwb_nopurple")) { + rtSettings.itcwb_nopurple = keyFile.get_boolean("Color Management", "Itcwb_nopurple"); + } + if (keyFile.has_key("Color Management", "Itcwb_stdobserver10")) { rtSettings.itcwb_stdobserver10 = keyFile.get_boolean("Color Management", "Itcwb_stdobserver10"); } @@ -2160,6 +2348,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_boolean("General", "Detectshape", rtSettings.detectshape); keyFile.set_boolean("General", "Fftwsigma", rtSettings.fftwsigma); + // TODO: Remove. keyFile.set_integer("External Editor", "EditorKind", editorToSendTo); keyFile.set_string("External Editor", "GimpDir", gimpDir); keyFile.set_string("External Editor", "PhotoshopDir", psDir); @@ -2169,6 +2358,24 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_boolean("External Editor", "Float32", editor_float32); keyFile.set_boolean("External Editor", "BypassOutputProfile", editor_bypass_output_profile); + { + std::vector names; + std::vector commands; + std::vector icons_serialized; + + for (const auto & editor : externalEditors) { + names.push_back(editor.name); + commands.push_back(editor.command); + icons_serialized.push_back(editor.icon_serialized); + } + + keyFile.set_string_list("External Editor", "Names", names); + keyFile.set_string_list("External Editor", "Commands", commands); + keyFile.set_string_list("External Editor", "IconsSerialized", icons_serialized); + + keyFile.set_integer("External Editor", "EditorIndex", externalEditorIndex); + } + keyFile.set_boolean("File Browser", "BrowseOnlyRaw", fbOnlyRaw); keyFile.set_boolean("File Browser", "BrowserShowsDate", fbShowDateTime); keyFile.set_boolean("File Browser", "BrowserShowsExif", fbShowBasicExif); @@ -2217,6 +2424,8 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string_list("File Browser", "RecentFolders", temp); } + keyFile.set_integer("File Browser", "SortMethod", sortMethod); + keyFile.set_boolean("File Browser", "SortDescending", sortDescending); keyFile.set_integer("Clipping Indication", "HighlightThreshold", highlightThreshold); keyFile.set_integer("Clipping Indication", "ShadowThreshold", shadowThreshold); keyFile.set_boolean("Clipping Indication", "BlinkClipped", blinkClipped); @@ -2243,6 +2452,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("Output", "TiffBps", saveFormat.tiffBits); keyFile.set_boolean("Output", "TiffFloat", saveFormat.tiffFloat); keyFile.set_boolean("Output", "TiffUncompressed", saveFormat.tiffUncompressed); + keyFile.set_boolean("Output", "BigTiff", saveFormat.bigTiff); keyFile.set_boolean("Output", "SaveProcParams", saveFormat.saveParams); keyFile.set_string("Output", "FormatBatch", saveFormatBatch.format); @@ -2277,6 +2487,7 @@ void Options::saveToFile(Glib::ustring fname) Glib::ArrayHandle ahfavorites = favorites; keyFile.set_string_list("GUI", "Favorites", ahfavorites); + keyFile.set_boolean("GUI", "FavoritesCloneTools", cloneFavoriteTools); keyFile.set_integer("GUI", "WindowWidth", windowWidth); keyFile.set_integer("GUI", "WindowHeight", windowHeight); keyFile.set_integer("GUI", "WindowX", windowX); @@ -2368,6 +2579,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("Color Management", "MonitorProfile", rtSettings.monitorProfile); keyFile.set_boolean("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile); keyFile.set_boolean("Color Management", "Autocielab", rtSettings.autocielab); + keyFile.set_boolean("Color Management", "Observer10", rtSettings.observer10); keyFile.set_boolean("Color Management", "RGBcurvesLumamode_Gamut", rtSettings.rgbcurveslumamode_gamut); keyFile.set_integer("Color Management", "Intent", rtSettings.monitorIntent); keyFile.set_boolean("Color Management", "MonitorBPC", rtSettings.monitorBPC); @@ -2401,10 +2613,11 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_double("Color Management", "CBDLlevel0", rtSettings.level0_cbdl); keyFile.set_double("Color Management", "CBDLlevel123", rtSettings.level123_cbdl); keyFile.set_integer("Color Management", "Itcwb_thres", rtSettings.itcwb_thres); - keyFile.set_boolean("Color Management", "Itcwb_sort", rtSettings.itcwb_sort); + keyFile.set_boolean("Color Management", "Itcwb_sorted", rtSettings.itcwb_sorted); keyFile.set_integer("Color Management", "Itcwb_greenrange", rtSettings.itcwb_greenrange); keyFile.set_integer("Color Management", "Itcwb_greendeltatemp", rtSettings.itcwb_greendeltatemp); keyFile.set_boolean("Color Management", "Itcwb_forceextra", rtSettings.itcwb_forceextra); + keyFile.set_boolean("Color Management", "Itcwb_nopurple", rtSettings.itcwb_nopurple); keyFile.set_integer("Color Management", "Itcwb_sizereference", rtSettings.itcwb_sizereference); keyFile.set_integer("Color Management", "Itcwb_delta", rtSettings.itcwb_delta); keyFile.set_boolean("Color Management", "Itcwb_stdobserver10", rtSettings.itcwb_stdobserver10); @@ -2836,3 +3049,19 @@ Glib::ustring Options::getICCProfileCopyright() now.set_time_current(); return Glib::ustring::compose("Copyright RawTherapee %1, CC0", now.get_year()); } + +ExternalEditor::ExternalEditor() {} + +ExternalEditor::ExternalEditor( + const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_serialized +): name(name), command(command), icon_serialized(icon_serialized) {} + +bool ExternalEditor::operator==(const ExternalEditor &other) const +{ + return this->name == other.name && this->command == other.command && this->icon_serialized == other.icon_serialized; +} + +bool ExternalEditor::operator!=(const ExternalEditor &other) const +{ + return !(*this == other); +} diff --git a/rtgui/options.h b/rtgui/options.h index bc5e41c91..5fb4e4f8b 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -52,6 +52,17 @@ // Special name for the Dynamic profile #define DEFPROFILE_DYNAMIC "Dynamic" +struct ExternalEditor { + ExternalEditor(); + ExternalEditor(const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_serialized); + Glib::ustring name; + Glib::ustring command; + Glib::ustring icon_serialized; + + bool operator==(const ExternalEditor & other) const; + bool operator!=(const ExternalEditor & other) const; +}; + struct SaveFormat { SaveFormat( const Glib::ustring& _format, @@ -61,6 +72,7 @@ struct SaveFormat { int _tiff_bits, bool _tiff_float, bool _tiff_uncompressed, + bool _big_tiff, bool _save_params ) : format(_format), @@ -70,6 +82,7 @@ struct SaveFormat { tiffBits(_tiff_bits), tiffFloat(_tiff_float), tiffUncompressed(_tiff_uncompressed), + bigTiff(_big_tiff), saveParams(_save_params) { } @@ -87,6 +100,7 @@ struct SaveFormat { _tiff_bits, _tiff_float, true, + false, true ) { @@ -103,6 +117,7 @@ struct SaveFormat { int tiffBits; bool tiffFloat; bool tiffUncompressed; + bool bigTiff; bool saveParams; }; @@ -276,6 +291,8 @@ public: Glib::ustring gimpDir; Glib::ustring psDir; Glib::ustring customEditorProg; + std::vector externalEditors; + int externalEditorIndex; Glib::ustring CPBPath; // Custom Profile Builder's path CPBKeyType CPBKeys; // Custom Profile Builder's key type int editorToSendTo; @@ -428,6 +445,7 @@ public: bool fastexport_use_fast_pipeline; std::vector favorites; + bool cloneFavoriteTools; // Dialog settings Glib::ustring lastIccDir; Glib::ustring lastDarkframeDir; @@ -452,6 +470,17 @@ public: size_t maxRecentFolders; // max. number of recent folders stored in options file std::vector recentFolders; // List containing all recent folders + enum SortMethod { + SORT_BY_NAME, + SORT_BY_DATE, + SORT_BY_EXIF, + SORT_BY_RANK, + SORT_BY_LABEL, + SORT_METHOD_COUNT, + }; + SortMethod sortMethod; // remembers current state of file browser + bool sortDescending; + Options (); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index a7963b7dc..abd4e8608 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -48,6 +48,7 @@ void ParamsEdited::set(bool v) toneCurve.shcompr = v; toneCurve.hlcompr = v; toneCurve.hlbl = v; + toneCurve.hlth = v; toneCurve.hlcomprthresh = v; toneCurve.autoexp = v; toneCurve.clip = v; @@ -104,7 +105,7 @@ void ParamsEdited::set(bool v) labCurve.brightness = v; labCurve.contrast = v; labCurve.chromaticity = v; - labCurve.avoidcolorshift = v; + labCurve.gamutmunselmethod = v; labCurve.rstprotection = v; labCurve.lcredsk = v; localContrast.enabled = v; @@ -254,7 +255,6 @@ void ParamsEdited::set(bool v) colorappearance.ybout = v; colorappearance.tempsc = v; colorappearance.greensc = v; - colorappearance.presetcat02 = v; //colorBoost.amount = v; //colorBoost.avoidclip = v; @@ -453,6 +453,7 @@ void ParamsEdited::set(bool v) icm.bluy = v; icm.preser = v; icm.fbw = v; + icm.gamut = v; icm.labgridcieALow = v; icm.labgridcieBLow = v; icm.labgridcieAHigh = v; @@ -519,6 +520,7 @@ void ParamsEdited::set(bool v) raw.df_autoselect = v; raw.ff_file = v; raw.ff_AutoSelect = v; + raw.ff_FromMetaData = v; raw.ff_BlurRadius = v; raw.ff_BlurType = v; raw.ff_AutoClipControl = v; @@ -748,6 +750,7 @@ void ParamsEdited::initFrom(const std::vector& toneCurve.shcompr = toneCurve.shcompr && p.toneCurve.shcompr == other.toneCurve.shcompr; toneCurve.hlcompr = toneCurve.hlcompr && p.toneCurve.hlcompr == other.toneCurve.hlcompr; toneCurve.hlbl = toneCurve.hlbl && p.toneCurve.hlbl == other.toneCurve.hlbl; + toneCurve.hlth = toneCurve.hlth && p.toneCurve.hlth == other.toneCurve.hlth; toneCurve.hlcomprthresh = toneCurve.hlcomprthresh && p.toneCurve.hlcomprthresh == other.toneCurve.hlcomprthresh; toneCurve.autoexp = toneCurve.autoexp && p.toneCurve.autoexp == other.toneCurve.autoexp; toneCurve.clip = toneCurve.clip && p.toneCurve.clip == other.toneCurve.clip; @@ -803,7 +806,7 @@ void ParamsEdited::initFrom(const std::vector& labCurve.brightness = labCurve.brightness && p.labCurve.brightness == other.labCurve.brightness; labCurve.contrast = labCurve.contrast && p.labCurve.contrast == other.labCurve.contrast; labCurve.chromaticity = labCurve.chromaticity && p.labCurve.chromaticity == other.labCurve.chromaticity; - labCurve.avoidcolorshift = labCurve.avoidcolorshift && p.labCurve.avoidcolorshift == other.labCurve.avoidcolorshift; + labCurve.gamutmunselmethod = labCurve.gamutmunselmethod && p.labCurve.gamutmunselmethod == other.labCurve.gamutmunselmethod; labCurve.rstprotection = labCurve.rstprotection && p.labCurve.rstprotection == other.labCurve.rstprotection; labCurve.lcredsk = labCurve.lcredsk && p.labCurve.lcredsk == other.labCurve.lcredsk; @@ -907,7 +910,6 @@ void ParamsEdited::initFrom(const std::vector& vibrance.avoidcolorshift = vibrance.avoidcolorshift && p.vibrance.avoidcolorshift == other.vibrance.avoidcolorshift; vibrance.pastsattog = vibrance.pastsattog && p.vibrance.pastsattog == other.vibrance.pastsattog; vibrance.skintonescurve = vibrance.skintonescurve && p.vibrance.skintonescurve == other.vibrance.skintonescurve; - colorappearance.enabled = colorappearance.enabled && p.colorappearance.enabled == other.colorappearance.enabled; colorappearance.degree = colorappearance.degree && p.colorappearance.degree == other.colorappearance.degree; colorappearance.autodegree = colorappearance.autodegree && p.colorappearance.autodegree == other.colorappearance.autodegree; @@ -954,7 +956,6 @@ void ParamsEdited::initFrom(const std::vector& colorappearance.ybout = colorappearance.ybout && p.colorappearance.ybout == other.colorappearance.ybout; colorappearance.tempsc = colorappearance.tempsc && p.colorappearance.tempsc == other.colorappearance.tempsc; colorappearance.greensc = colorappearance.greensc && p.colorappearance.greensc == other.colorappearance.greensc; - colorappearance.presetcat02 = colorappearance.presetcat02 && p.colorappearance.presetcat02 == other.colorappearance.presetcat02; //colorBoost.amount = colorBoost.amount && p.colorBoost.amount == other.colorBoost.amount; //colorBoost.avoidclip = colorBoost.avoidclip && p.colorBoost.avoidclip == other.colorBoost.avoidclip; @@ -1090,6 +1091,7 @@ void ParamsEdited::initFrom(const std::vector& 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).avoidgamutMethod = locallab.spots.at(j).avoidgamutMethod && pSpot.avoidgamutMethod == otherSpot.avoidgamutMethod; 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; @@ -1109,8 +1111,6 @@ void ParamsEdited::initFrom(const std::vector& 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).avoidmun = locallab.spots.at(j).avoidmun && pSpot.avoidmun == otherSpot.avoidmun; 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; @@ -1872,6 +1872,7 @@ void ParamsEdited::initFrom(const std::vector& icm.labgridcieWy = icm.labgridcieWy && p.icm.labgridcieWy == other.icm.labgridcieWy; icm.preser = icm.preser && p.icm.preser == other.icm.preser; icm.fbw = icm.fbw && p.icm.fbw == other.icm.fbw; + icm.gamut = icm.gamut && p.icm.gamut == other.icm.gamut; icm.aRendIntent = icm.aRendIntent && p.icm.aRendIntent == other.icm.aRendIntent; icm.workingTRC = icm.workingTRC && p.icm.workingTRC == other.icm.workingTRC; icm.will = icm.will && p.icm.will == other.icm.will; @@ -1930,6 +1931,7 @@ void ParamsEdited::initFrom(const std::vector& raw.df_autoselect = raw.df_autoselect && p.raw.df_autoselect == other.raw.df_autoselect; raw.ff_file = raw.ff_file && p.raw.ff_file == other.raw.ff_file; raw.ff_AutoSelect = raw.ff_AutoSelect && p.raw.ff_AutoSelect == other.raw.ff_AutoSelect; + raw.ff_FromMetaData = raw.ff_FromMetaData && p.raw.ff_FromMetaData == other.raw.ff_FromMetaData; raw.ff_BlurRadius = raw.ff_BlurRadius && p.raw.ff_BlurRadius == other.raw.ff_BlurRadius; raw.ff_BlurType = raw.ff_BlurType && p.raw.ff_BlurType == other.raw.ff_BlurType; raw.ff_AutoClipControl = raw.ff_AutoClipControl && p.raw.ff_AutoClipControl == other.raw.ff_AutoClipControl; @@ -2192,6 +2194,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.toneCurve.hlbl = mods.toneCurve.hlbl; } + if (toneCurve.hlth) { + toEdit.toneCurve.hlth = mods.toneCurve.hlth; + } + if (toneCurve.histmatching) { toEdit.toneCurve.histmatching = mods.toneCurve.histmatching; } @@ -2390,8 +2396,8 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.labCurve.chromaticity = dontforceSet && options.baBehav[ADDSET_LC_CHROMATICITY] ? toEdit.labCurve.chromaticity + mods.labCurve.chromaticity : mods.labCurve.chromaticity; } - if (labCurve.avoidcolorshift) { - toEdit.labCurve.avoidcolorshift = mods.labCurve.avoidcolorshift; + if (labCurve.gamutmunselmethod) { + toEdit.labCurve.gamutmunselmethod = mods.labCurve.gamutmunselmethod; } if (labCurve.rstprotection) { @@ -3032,9 +3038,6 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.colorappearance.tonecie = mods.colorappearance.tonecie; } - if (colorappearance.presetcat02) { - toEdit.colorappearance.presetcat02 = mods.colorappearance.presetcat02; - } // if (colorappearance.sharpcie) toEdit.colorappearance.sharpcie = mods.colorappearance.sharpcie; if (impulseDenoise.enabled) { @@ -3435,6 +3438,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).shapeMethod = mods.locallab.spots.at(i).shapeMethod; } + if (locallab.spots.at(i).avoidgamutMethod) { + toEdit.locallab.spots.at(i).avoidgamutMethod = mods.locallab.spots.at(i).avoidgamutMethod; + } + if (locallab.spots.at(i).loc) { toEdit.locallab.spots.at(i).loc = mods.locallab.spots.at(i).loc; } @@ -3511,14 +3518,6 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng 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).avoidmun) { - toEdit.locallab.spots.at(i).avoidmun = mods.locallab.spots.at(i).avoidmun; - } - if (locallab.spots.at(i).blwh) { toEdit.locallab.spots.at(i).blwh = mods.locallab.spots.at(i).blwh; } @@ -6380,6 +6379,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.icm.fbw = mods.icm.fbw; } + if (icm.gamut) { + toEdit.icm.gamut = mods.icm.gamut; + } + if (icm.labgridcieALow) { toEdit.icm.labgridcieALow = mods.icm.labgridcieALow; } @@ -6644,6 +6647,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.raw.ff_AutoSelect = mods.raw.ff_AutoSelect; } + if (raw.ff_FromMetaData) { + toEdit.raw.ff_FromMetaData = mods.raw.ff_FromMetaData; + } + if (raw.ff_BlurRadius) { toEdit.raw.ff_BlurRadius = mods.raw.ff_BlurRadius; } @@ -7375,7 +7382,7 @@ bool RAWParamsEdited::XTransSensor::isUnchanged() const bool RAWParamsEdited::isUnchanged() const { return bayersensor.isUnchanged() && xtranssensor.isUnchanged() && ca_autocorrect && ca_avoidcolourshift && caautoiterations && cared && cablue && hotPixelFilter && deadPixelFilter && hotdeadpix_thresh && darkFrame - && df_autoselect && ff_file && ff_AutoSelect && ff_BlurRadius && ff_BlurType && exPos && ff_AutoClipControl && ff_clipControl; + && df_autoselect && ff_file && ff_AutoSelect && ff_FromMetaData && ff_BlurRadius && ff_BlurType && exPos && ff_AutoClipControl && ff_clipControl; } bool LensProfParamsEdited::isUnchanged() const @@ -7405,6 +7412,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : structexclu(v), struc(v), shapeMethod(v), + avoidgamutMethod(v), loc(v), centerX(v), centerY(v), @@ -7424,8 +7432,6 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : transitgrad(v), hishow(v), activ(v), - avoid(v), - avoidmun(v), blwh(v), recurs(v), laplac(v), @@ -8097,6 +8103,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) structexclu = v; struc = v; shapeMethod = v; + avoidgamutMethod = v; loc = v; centerX = v; centerY = v; @@ -8116,8 +8123,6 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) transitgrad = v; hishow = v; activ = v; - avoid = v; - avoidmun = v; blwh = v; recurs = v; laplac = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 0c0c79f7c..66db8346f 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -52,6 +52,7 @@ struct ToneCurveParamsEdited { bool shcompr; bool hlcompr; bool hlbl; + bool hlth; bool hlcomprthresh; bool autoexp; bool clip; @@ -109,7 +110,7 @@ struct LCurveParamsEdited { bool brightness; bool contrast; bool chromaticity; - bool avoidcolorshift; + bool gamutmunselmethod; bool rstprotection; bool lcurve; bool acurve; @@ -305,7 +306,6 @@ struct ColorAppearanceParamsEdited { bool ybout; bool tempsc; bool greensc; - bool presetcat02; }; struct DirPyrDenoiseParamsEdited { @@ -403,6 +403,7 @@ public: bool structexclu; bool struc; bool shapeMethod; + bool avoidgamutMethod; bool loc; bool centerX; bool centerY; @@ -422,8 +423,6 @@ public: bool transitgrad; bool hishow; bool activ; - bool avoid; - bool avoidmun; bool blwh; bool recurs; bool laplac; @@ -1231,6 +1230,7 @@ struct ColorManagementParamsEdited { bool bluy; bool preser; bool fbw; + bool gamut; bool labgridcieALow; bool labgridcieBLow; bool labgridcieAHigh; @@ -1489,6 +1489,7 @@ struct RAWParamsEdited { bool df_autoselect; bool ff_file; bool ff_AutoSelect; + bool ff_FromMetaData; bool ff_BlurRadius; bool ff_BlurType; bool ff_AutoClipControl; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index a9f79d854..81847adc0 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -301,6 +301,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren //--- ff_file = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDFILE"))); ff_AutoSelect = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDAUTOSELECT"))); + ff_FromMetaData = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDFROMMETADATA"))); ff_BlurType = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDBLURTYPE"))); ff_BlurRadius = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDBLURRADIUS"))); ff_ClipControl = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDCLIPCONTROL"))); @@ -423,6 +424,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[8]->pack_start (*Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), 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_FromMetaData, 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); @@ -574,6 +576,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren //--- ff_fileConn = ff_file->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); ff_AutoSelectConn = ff_AutoSelect->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); + ff_FromMetaDataConn = ff_FromMetaData->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); ff_BlurTypeConn = ff_BlurType->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); ff_BlurRadiusConn = ff_BlurRadius->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); ff_ClipControlConn = ff_ClipControl->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); @@ -655,6 +658,7 @@ void PartialPasteDlg::rawToggled () ConnectionBlocker df_AutoSelectBlocker(df_AutoSelectConn); ConnectionBlocker ff_fileBlocker(ff_fileConn); ConnectionBlocker ff_AutoSelectBlocker(ff_AutoSelectConn); + ConnectionBlocker ff_FromMetaDataBlocker(ff_FromMetaDataConn); ConnectionBlocker ff_BlurTypeBlocker(ff_BlurTypeConn); ConnectionBlocker ff_BlurRadiusBlocker(ff_BlurRadiusConn); ConnectionBlocker ff_ClipControlBlocker(ff_ClipControlConn); @@ -685,6 +689,7 @@ void PartialPasteDlg::rawToggled () df_AutoSelect->set_active (raw->get_active ()); ff_file->set_active (raw->get_active ()); ff_AutoSelect->set_active (raw->get_active ()); + ff_FromMetaData->set_active (raw->get_active ()); ff_BlurType->set_active (raw->get_active ()); ff_BlurRadius->set_active (raw->get_active ()); ff_ClipControl->set_active (raw->get_active ()); @@ -1173,6 +1178,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.raw.ff_AutoSelect = falsePE.raw.ff_AutoSelect; } + if (!ff_FromMetaData->get_active ()) { + filterPE.raw.ff_FromMetaData = falsePE.raw.ff_FromMetaData; + } + if (!ff_BlurRadius->get_active ()) { filterPE.raw.ff_BlurRadius = falsePE.raw.ff_BlurRadius; } diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 19e1eb462..dcf44bb72 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -214,6 +214,7 @@ public: Gtk::CheckButton* df_AutoSelect; Gtk::CheckButton* ff_file; Gtk::CheckButton* ff_AutoSelect; + Gtk::CheckButton* ff_FromMetaData; Gtk::CheckButton* ff_BlurRadius; Gtk::CheckButton* ff_BlurType; Gtk::CheckButton* ff_ClipControl; @@ -230,7 +231,7 @@ public: sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn; sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, prsharpeningConn, perspectiveConn, commonTransConn; sigc::connection metadataConn, exifchConn, iptcConn, icmConn; - sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_BlurRadiusConn, ff_BlurTypeConn, ff_ClipControlConn; + sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_FromMetaDataConn, ff_BlurRadiusConn, ff_BlurTypeConn, ff_ClipControlConn; sigc::connection raw_caredblueConn, raw_ca_autocorrectConn, raw_ca_avoid_colourshiftconn, raw_hotpix_filtConn, raw_deadpix_filtConn, raw_pdaf_lines_filterConn, raw_linenoiseConn, raw_greenthreshConn, raw_ccStepsConn, raw_methodConn, raw_borderConn, raw_imagenumConn, raw_dcb_iterationsConn, raw_lmmse_iterationsConn, raw_pixelshiftConn, raw_dcb_enhanceConn, raw_exposConn, raw_blackConn; sigc::connection filmNegativeConn; sigc::connection captureSharpeningConn; diff --git a/rtgui/pcvignette.cc b/rtgui/pcvignette.cc index 9c141d618..1ed7446b1 100644 --- a/rtgui/pcvignette.cc +++ b/rtgui/pcvignette.cc @@ -8,7 +8,9 @@ using namespace rtengine; using namespace rtengine::procparams; -PCVignette::PCVignette () : FoldableToolPanel(this, "pcvignette", M("TP_PCVIGNETTE_LABEL"), false, true) +const Glib::ustring PCVignette::TOOL_NAME = "pcvignette"; + +PCVignette::PCVignette () : FoldableToolPanel(this, TOOL_NAME, M("TP_PCVIGNETTE_LABEL"), false, true) { strength = Gtk::manage (new Adjuster (M("TP_PCVIGNETTE_STRENGTH"), -6, 6, 0.01, 0)); strength->set_tooltip_text (M("TP_PCVIGNETTE_STRENGTH_TOOLTIP")); diff --git a/rtgui/pcvignette.h b/rtgui/pcvignette.h index 87915703f..825654630 100644 --- a/rtgui/pcvignette.h +++ b/rtgui/pcvignette.h @@ -20,6 +20,7 @@ protected: Adjuster* roundness; public: + static const Glib::ustring TOOL_NAME; PCVignette (); diff --git a/rtgui/pdsharpening.cc b/rtgui/pdsharpening.cc index 45d5b545c..57133048c 100644 --- a/rtgui/pdsharpening.cc +++ b/rtgui/pdsharpening.cc @@ -31,8 +31,10 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring PdSharpening::TOOL_NAME = "capturesharpening"; + PdSharpening::PdSharpening() : - FoldableToolPanel(this, "capturesharpening", M("TP_PDSHARPENING_LABEL"), false, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_PDSHARPENING_LABEL"), false, true), lastAutoContrast(true), lastAutoRadius(true) { diff --git a/rtgui/pdsharpening.h b/rtgui/pdsharpening.h index eb0576ceb..c4902e4b6 100644 --- a/rtgui/pdsharpening.h +++ b/rtgui/pdsharpening.h @@ -50,6 +50,7 @@ protected: IdleRegister idle_register; public: + static const Glib::ustring TOOL_NAME; PdSharpening (); ~PdSharpening () override; diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index af182617e..e46598912 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -27,6 +27,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring PerspCorrection::TOOL_NAME = "perspective"; + namespace { @@ -84,7 +86,7 @@ std::vector valuesToControlLines( } -PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M("TP_PERSPECTIVE_LABEL")) +PerspCorrection::PerspCorrection () : FoldableToolPanel(this, TOOL_NAME, M("TP_PERSPECTIVE_LABEL")) { auto mapper = ProcEventMapper::getInstance(); diff --git a/rtgui/perspective.h b/rtgui/perspective.h index 404b02010..6ca2381e3 100644 --- a/rtgui/perspective.h +++ b/rtgui/perspective.h @@ -104,6 +104,7 @@ public: static constexpr std::size_t MIN_HORIZ_LINES = 2; /** Minimum number of vertical lines for vertical/full correction. */ static constexpr std::size_t MIN_VERT_LINES = 2; + static const Glib::ustring TOOL_NAME; PerspCorrection (); diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index 69d51f2dd..54c727bf7 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -27,7 +27,7 @@ PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) : buttonImage (nullptr) - , menu (nullptr) + , menu(new Gtk::Menu()) , selected (-1) // -1 means that the button is invalid { button = thisButton; @@ -48,58 +48,153 @@ PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) setExpandAlignProperties(buttonGroup, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); buttonGroup->attach(*button, 0, 0, 1, 1); buttonGroup->get_style_context()->add_class("image-combo"); + + // Create the image for the button + buttonImage = Gtk::manage(new RTImage()); + setExpandAlignProperties(buttonImage, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + imageContainer->attach_next_to(*buttonImage, Gtk::POS_RIGHT, 1, 1); + buttonImage->set_no_show_all(); + + // Create the button for showing the pop-up. + arrowButton = Gtk::manage(new Gtk::Button()); + Gtk::Image *arrowImage = Gtk::manage(new Gtk::Image()); + arrowImage->set_from_icon_name("pan-down-symbolic", Gtk::ICON_SIZE_BUTTON); + setExpandAlignProperties(arrowButton, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); + arrowButton->add(*arrowImage); //menuSymbol); + arrowImage->show(); + buttonGroup->attach_next_to(*arrowButton, *button, Gtk::POS_RIGHT, 1, 1); + arrowButton->signal_button_release_event().connect_notify(sigc::mem_fun(*this, &PopUpCommon::showMenu)); + arrowButton->get_style_context()->add_class("Right"); + arrowButton->get_style_context()->add_class("popupbutton-arrow"); + arrowButton->set_no_show_all(); } PopUpCommon::~PopUpCommon () { - delete menu; - delete buttonImage; } -bool PopUpCommon::addEntry (const Glib::ustring& iconName, const Glib::ustring& label) +bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup) { - if (label.empty ()) - return false; + return insertEntry(getEntryCount(), fileName, label, radioGroup); +} + +bool PopUpCommon::insertEntry(int position, const Glib::ustring& iconName, const Glib::ustring& label, Gtk::RadioButtonGroup *radioGroup) +{ + RTImage* image = nullptr; + if (!iconName.empty()) { + image = Gtk::manage(new RTImage(iconName)); + } + bool success = insertEntryImpl(position, iconName, Glib::RefPtr(), image, label, radioGroup); + if (!success && image) { + delete image; + } + return success; +} + +bool PopUpCommon::insertEntry(int position, const Glib::RefPtr& gIcon, const Glib::ustring& label, Gtk::RadioButtonGroup *radioGroup) +{ + auto image = Gtk::manage(new RTImage(gIcon, Gtk::ICON_SIZE_BUTTON)); + bool success = insertEntryImpl(position, "", gIcon, image, label, radioGroup); + if (!success) { + delete image; + } + return success; +} + +bool PopUpCommon::insertEntryImpl(int position, const Glib::ustring& iconName, const Glib::RefPtr& gIcon, RTImage* image, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup) +{ + if (label.empty() || position < 0 || position > getEntryCount()) + return false; // Create the menu item and image - MyImageMenuItem* newItem = Gtk::manage (new MyImageMenuItem (label, iconName)); - imageFilenames.push_back (iconName); - images.push_back (newItem->getImage ()); - - if (selected == -1) { - // Create the menu on the first item - menu = new Gtk::Menu (); - // Create the image for the button - buttonImage = new RTImage(iconName, Gtk::ICON_SIZE_BUTTON); - setExpandAlignProperties(buttonImage, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - // Use the first image by default - imageContainer->attach_next_to(*buttonImage, Gtk::POS_RIGHT, 1, 1); - selected = 0; + Gtk::MenuItem *newItem; + if (radioGroup) { + newItem = Gtk::manage(new MyRadioImageMenuItem(label, image, *radioGroup)); } + else { + newItem = Gtk::manage(new MyImageMenuItem(label, image)); + } + imageIcons.insert(imageIcons.begin() + position, gIcon); + imageIconNames.insert(imageIconNames.begin() + position, iconName); + images.insert(images.begin() + position, image); // When there is at least 1 choice, we add the arrow button if (images.size() == 1) { - Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() ); - Gtk::Image *arrowImage = Gtk::manage(new RTImage("pan-down-symbolic", Gtk::ICON_SIZE_BUTTON)); - setExpandAlignProperties(arrowButton, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - arrowButton->add(*arrowImage); //menuSymbol); - buttonGroup->attach_next_to(*arrowButton, *button, Gtk::POS_RIGHT, 1, 1); - arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) ); + changeImage(iconName, gIcon); + buttonImage->show(); + selected = 0; button->get_style_context()->add_class("Left"); - arrowButton->get_style_context()->add_class("Right"); - arrowButton->get_style_context()->add_class("popupbutton-arrow"); + arrowButton->show(); hasMenu = true; + } else if (position <= selected) { + selected++; } - newItem->signal_activate ().connect (sigc::bind (sigc::mem_fun (*this, &PopUpCommon::entrySelected), images.size () - 1)); - menu->append (*newItem); - + void (PopUpCommon::*entrySelectedFunc)(Gtk::Widget *) = &PopUpCommon::entrySelected; + newItem->signal_activate ().connect (sigc::bind (sigc::mem_fun (*this, entrySelectedFunc), newItem)); + menu->insert(*newItem, position); return true; } -// TODO: 'PopUpCommon::removeEntry' method to be created... +void PopUpCommon::removeEntry(int position) +{ + if (position < 0 || position >= getEntryCount()) { + return; + } -void PopUpCommon::entrySelected (int i) + if (getEntryCount() == 1) { // Last of the entries. + // Hide the arrow button. + button->get_style_context()->remove_class("Left"); + arrowButton->hide(); + hasMenu = false; + // Remove the button image. + buttonImage->hide(); + selected = -1; + } + else if (position < selected) { + selected--; + } + else if (position == selected) { // Select a different entry before removing. + int nextSelection = position + (position == getEntryCount() - 1 ? -1 : 1); + changeImage(nextSelection); + setButtonHint(); + } + + std::unique_ptr menuItem(menu->get_children()[position]); + menu->remove(*menuItem); + imageIcons.erase(imageIcons.begin() + position); + imageIconNames.erase(imageIconNames.begin() + position); + images.erase(images.begin() + position); +} + +void PopUpCommon::changeImage(int position) +{ + changeImage(imageIconNames.at(position), imageIcons.at(position)); +} + +void PopUpCommon::changeImage(const Glib::ustring& iconName, const Glib::RefPtr& gIcon) +{ + if (!iconName.empty()) { + buttonImage->set_from_icon_name(iconName, Gtk::ICON_SIZE_BUTTON); + } else { + buttonImage->set_from_gicon(gIcon, Gtk::ICON_SIZE_BUTTON); + } +} + +void PopUpCommon::entrySelected(Gtk::Widget* widget) +{ + int i = 0; + for (const auto & child : menu->get_children()) { + if (widget == child) { + break; + } + i++; + } + + entrySelected(i); +} + +void PopUpCommon::entrySelected(int i) { // Emit a signal if the selected item has changed if (setSelected (posToIndex(i))) @@ -129,9 +224,15 @@ bool PopUpCommon::setSelected (int entryNum) return false; } else { // Maybe we could do something better than loading the image file each time the selection is changed !? - buttonImage->set_from_icon_name(imageFilenames.at(entryNum), Gtk::ICON_SIZE_BUTTON); + changeImage(entryNum); selected = entryNum; setButtonHint(); + + auto radioMenuItem = dynamic_cast(menu->get_children()[entryNum]); + if (radioMenuItem && menu->get_active() != radioMenuItem) { + radioMenuItem->set_active(); + } + return true; } } @@ -158,10 +259,10 @@ void PopUpCommon::setButtonHint() if (selected > -1) { auto widget = menu->get_children ()[selected]; - auto item = dynamic_cast(widget); + auto item = dynamic_cast(widget); if (item) { - hint += item->getLabel ()->get_text (); + hint += escapeHtmlChars(item->getLabel()->get_text()); } } diff --git a/rtgui/popupcommon.h b/rtgui/popupcommon.h index b4cf4d7e0..9ca6b2030 100644 --- a/rtgui/popupcommon.h +++ b/rtgui/popupcommon.h @@ -20,12 +20,19 @@ */ #pragma once +#include "glibmm/refptr.h" +#include #include #include #include +namespace Gio +{ +class Icon; +} + namespace Gtk { @@ -33,6 +40,8 @@ class Grid; class Menu; class Button; class ImageMenuItem; +class RadioButtonGroup; +class Widget; } @@ -52,10 +61,13 @@ public: explicit PopUpCommon (Gtk::Button* button, const Glib::ustring& label = ""); virtual ~PopUpCommon (); - bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label); + bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup = nullptr); + bool insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup = nullptr); + bool insertEntry(int position, const Glib::RefPtr& gIcon, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup = nullptr); int getEntryCount () const; bool setSelected (int entryNum); int getSelected () const; + void removeEntry(int position); void setButtonHint(); void show (); void set_tooltip_text (const Glib::ustring &text); @@ -65,16 +77,22 @@ private: type_signal_changed messageChanged; type_signal_item_selected messageItemSelected; + std::vector> imageIcons; std::vector imageFilenames; std::vector images; Glib::ustring buttonHint; RTImage* buttonImage; Gtk::Grid* imageContainer; - Gtk::Menu* menu; + std::unique_ptr menu; Gtk::Button* button; + Gtk::Button* arrowButton; int selected; bool hasMenu; + void changeImage(int position); + void changeImage(const Glib::ustring& fileName, const Glib::RefPtr& gIcon); + void entrySelected(Gtk::Widget* menuItem); + bool insertEntryImpl(int position, const Glib::ustring& fileName, const Glib::RefPtr& gIcon, RTImage* image, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup); void showMenu(GdkEventButton* event); protected: diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 805e64e28..00cecb610 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ #include +#include "externaleditorpreferences.h" #include "preferences.h" #include "multilangmgr.h" #include "splash.h" @@ -29,6 +30,7 @@ #include #include "rtimage.h" #include "rtwindow.h" +#include "toollocationpref.h" #ifdef _OPENMP #include #endif @@ -65,6 +67,8 @@ Preferences::Preferences(RTWindow *rtwindow) , parent(rtwindow) , newFont(false) , newCPFont(false) + , toolLocationPreference(nullptr) + , swFavorites(nullptr) { moptions.copyFrom(&options); @@ -102,6 +106,7 @@ Preferences::Preferences(RTWindow *rtwindow) nb->append_page(*getGeneralPanel(), M("PREFERENCES_TAB_GENERAL")); nb->append_page(*getImageProcessingPanel(), M("PREFERENCES_TAB_IMPROC")); + nb->append_page(*getFavoritesPanel(), M("PREFERENCES_TAB_FAVORITES")); nb->append_page(*getDynamicProfilePanel(), M("PREFERENCES_TAB_DYNAMICPROFILE")); nb->append_page(*getFileBrowserPanel(), M("PREFERENCES_TAB_BROWSER")); nb->append_page(*getColorManPanel(), M("PREFERENCES_TAB_COLORMGR")); @@ -492,6 +497,18 @@ void Preferences::behSetRadioToggled(const Glib::ustring& path) behAddSetRadioToggled(path, false); } +Gtk::Widget *Preferences::getFavoritesPanel() +{ + if (!toolLocationPreference) { + toolLocationPreference = Gtk::manage(new ToolLocationPreference(moptions)); + } + if (!swFavorites) { + swFavorites = Gtk::manage(new Gtk::ScrolledWindow()); + swFavorites->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_NEVER); + swFavorites->add(*toolLocationPreference); + } + return swFavorites; +} Gtk::Widget *Preferences::getDynamicProfilePanel() { @@ -1202,68 +1219,16 @@ Gtk::Widget* Preferences::getGeneralPanel() 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); - 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); - - 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); -#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); - - 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); -#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); - - externaleditorGrid->attach_next_to(*edOther, *edGimp, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); -#endif + externalEditors = Gtk::manage(new ExternalEditorPreferences()); + externalEditors->set_size_request(-1, 200); // fdg->add(*externaleditorGrid); editor_dir_temp = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_TEMP"))); editor_dir_current = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CURRENT"))); editor_dir_custom = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CUSTOM") + ": ")); editor_dir_custom_path = Gtk::manage(new MyFileChooserButton("", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + Gtk::RadioButton::Group ge; ge = editor_dir_temp->get_group(); editor_dir_current->set_group(ge); editor_dir_custom->set_group(ge); @@ -1272,7 +1237,7 @@ Gtk::Widget* Preferences::getGeneralPanel() editor_bypass_output_profile = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_EXTEDITOR_BYPASS_OUTPUT_PROFILE"))); { Gtk::Frame *f = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTEDITOR_DIR"))); - setExpandAlignProperties(f, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(f, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); Gtk::Box *vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); vb->pack_start(*editor_dir_temp); vb->pack_start(*editor_dir_current); @@ -1283,7 +1248,7 @@ Gtk::Widget* Preferences::getGeneralPanel() f->add(*vb); hb = Gtk::manage(new Gtk::Box()); - hb->pack_start(*externaleditorGrid); + hb->pack_start(*externalEditors); hb->pack_start(*f, Gtk::PACK_EXPAND_WIDGET, 4); vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); @@ -1755,31 +1720,17 @@ void Preferences::storePreferences() moptions.pseudoHiDPISupport = pseudoHiDPI->get_active(); -#ifdef WIN32 - moptions.gimpDir = gimpDir->get_filename(); - moptions.psDir = psDir->get_filename(); -#elif defined __APPLE__ - moptions.psDir = psDir->get_filename(); -#endif - moptions.customEditorProg = editorToSendTo->get_text(); - - if (edGimp->get_active()) { - moptions.editorToSendTo = 1; - } - -#ifdef WIN32 - else if (edPS->get_active()) { - moptions.editorToSendTo = 2; - } - -#elif defined __APPLE__ - else if (edPS->get_active()) { - moptions.editorToSendTo = 2; - } - -#endif - else if (edOther->get_active()) { - moptions.editorToSendTo = 3; + const std::vector &editors = externalEditors->getEditors(); + moptions.externalEditors.resize(editors.size()); + moptions.externalEditorIndex = -1; + for (unsigned i = 0; i < editors.size(); i++) { + moptions.externalEditors[i] = (ExternalEditor( + editors[i].name, editors[i].command, editors[i].icon_serialized)); + if (editors[i].other_data) { + // The current editor was marked before the list was edited. We + // found the mark, so this is the editor that was active. + moptions.externalEditorIndex = i; + } } if (editor_dir_temp->get_active()) { @@ -1938,6 +1889,8 @@ void Preferences::storePreferences() moptions.cropGuides = Options::CropGuidesMode(cropGuidesCombo->get_active_row_number()); moptions.cropAutoFit = cropAutoFitCB->get_active(); + + toolLocationPreference->updateOptions(); } void Preferences::fillPreferences() @@ -2050,34 +2003,16 @@ void Preferences::fillPreferences() hlThresh->set_value(moptions.highlightThreshold); shThresh->set_value(moptions.shadowThreshold); - edGimp->set_active(moptions.editorToSendTo == 1); - edOther->set_active(moptions.editorToSendTo == 3); -#ifdef WIN32 - edPS->set_active(moptions.editorToSendTo == 2); - - 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()); + std::vector editorInfos; + for (const auto &editor : moptions.externalEditors) { + editorInfos.push_back(ExternalEditorPreferences::EditorInfo( + editor.name, editor.command, editor.icon_serialized)); } - - 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()); + if (moptions.externalEditorIndex >= 0) { + // Mark the current editor so we can track it. + editorInfos[moptions.externalEditorIndex].other_data = (void *)1; } - -#elif defined __APPLE__ - edPS->set_active(moptions.editorToSendTo == 2); - - 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()); - } - -#endif - editorToSendTo->set_text(moptions.customEditorProg); + externalEditors->setEditors(editorInfos); editor_dir_temp->set_active(moptions.editor_out_dir == Options::EDITOR_OUT_DIR_TEMP); editor_dir_current->set_active(moptions.editor_out_dir == Options::EDITOR_OUT_DIR_CURRENT); @@ -2552,6 +2487,28 @@ void Preferences::workflowUpdate() parent->updateProfiles (moptions.rtSettings.printerProfile, rtengine::RenderingIntent(moptions.rtSettings.printerIntent), moptions.rtSettings.printerBPC); } + bool changed = moptions.externalEditorIndex != options.externalEditorIndex + || moptions.externalEditors.size() != options.externalEditors.size(); + if (!changed) { + auto &editors = options.externalEditors; + auto &meditors = moptions.externalEditors; + for (unsigned i = 0; i < editors.size(); i++) { + if (editors[i] != meditors[i]) { + changed = true; + break; + } + } + } + if (changed) { + // Update the send to external editor widget. + parent->updateExternalEditorWidget(moptions.externalEditorIndex, moptions.externalEditors); + } + + if (moptions.cloneFavoriteTools != options.cloneFavoriteTools || + moptions.favorites != options.favorites) { + parent->updateToolPanelToolLocations( + moptions.favorites, moptions.cloneFavoriteTools); + } } void Preferences::addExtPressed() diff --git a/rtgui/preferences.h b/rtgui/preferences.h index dfe1e008d..90ea20da7 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -26,8 +26,10 @@ #include "options.h" #include "../rtengine/profilestore.h" +class ExternalEditorPreferences; class RTWindow; class Splash; +class ToolLocationPreference; class Preferences final : public Gtk::Dialog, @@ -101,6 +103,7 @@ class Preferences final : Gtk::RadioButton* edGimp; Gtk::RadioButton* edPS; Gtk::RadioButton* edOther; + ExternalEditorPreferences *externalEditors; Gtk::RadioButton *editor_dir_temp; Gtk::RadioButton *editor_dir_current; @@ -244,6 +247,8 @@ class Preferences final : bool newFont; bool newCPFont; + ToolLocationPreference *toolLocationPreference; + void fillPreferences (); void storePreferences (); void parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext); @@ -269,6 +274,7 @@ class Preferences final : Gtk::ScrolledWindow *swGeneral; Gtk::ScrolledWindow *swImageProcessing; + Gtk::ScrolledWindow *swFavorites; Gtk::ScrolledWindow *swDynamicProfile; Gtk::ScrolledWindow *swFileBrowser; Gtk::ScrolledWindow *swColorMan; @@ -278,6 +284,7 @@ class Preferences final : Gtk::Widget *getGeneralPanel(); Gtk::Widget *getImageProcessingPanel(); + Gtk::Widget *getFavoritesPanel(); Gtk::Widget *getDynamicProfilePanel(); Gtk::Widget *getFileBrowserPanel(); Gtk::Widget *getColorManPanel(); diff --git a/rtgui/preprocess.cc b/rtgui/preprocess.cc index b9326e3ad..4d7df213c 100644 --- a/rtgui/preprocess.cc +++ b/rtgui/preprocess.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -PreProcess::PreProcess () : FoldableToolPanel(this, "preprocess", M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar) +const Glib::ustring PreProcess::TOOL_NAME = "preprocess"; + +PreProcess::PreProcess () : FoldableToolPanel(this, TOOL_NAME, M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar) { Gtk::Box* hotdeadPixel = Gtk::manage( new Gtk::Box () ); diff --git a/rtgui/preprocess.h b/rtgui/preprocess.h index d10ff5223..047413bdb 100644 --- a/rtgui/preprocess.h +++ b/rtgui/preprocess.h @@ -38,6 +38,7 @@ protected: sigc::connection dpixelconn; Adjuster* hdThreshold; public: + static const Glib::ustring TOOL_NAME; PreProcess (); diff --git a/rtgui/preprocesswb.cc b/rtgui/preprocesswb.cc index dddd7fdc2..9251f9440 100644 --- a/rtgui/preprocesswb.cc +++ b/rtgui/preprocesswb.cc @@ -29,8 +29,10 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring PreprocessWB::TOOL_NAME = "preprocesswb"; + PreprocessWB::PreprocessWB() : - FoldableToolPanel(this, "preprocesswb", M("TP_PREPROCWB_LABEL")), + FoldableToolPanel(this, TOOL_NAME, M("TP_PREPROCWB_LABEL")), evPreprocessWBMode(ProcEventMapper::getInstance()->newEvent(FIRST, "HISTORY_MSG_PREPROCWB_MODE")), mode(Gtk::manage(new MyComboBoxText())) { diff --git a/rtgui/preprocesswb.h b/rtgui/preprocesswb.h index 343d2e9e9..08e1dc468 100644 --- a/rtgui/preprocesswb.h +++ b/rtgui/preprocesswb.h @@ -34,6 +34,7 @@ private: MyComboBoxText* mode; public: + static const Glib::ustring TOOL_NAME; PreprocessWB(); diff --git a/rtgui/prsharpening.cc b/rtgui/prsharpening.cc index c79fff1a1..d3c936fa2 100644 --- a/rtgui/prsharpening.cc +++ b/rtgui/prsharpening.cc @@ -23,7 +23,9 @@ using namespace rtengine; using namespace rtengine::procparams; -PrSharpening::PrSharpening () : FoldableToolPanel(this, "prsharpening", M("TP_PRSHARPENING_LABEL"), false, true) +const Glib::ustring PrSharpening::TOOL_NAME = "prsharpening"; + +PrSharpening::PrSharpening () : FoldableToolPanel(this, TOOL_NAME, M("TP_PRSHARPENING_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); diff --git a/rtgui/prsharpening.h b/rtgui/prsharpening.h index 4128bc4c5..ea22234f8 100644 --- a/rtgui/prsharpening.h +++ b/rtgui/prsharpening.h @@ -59,6 +59,7 @@ protected: sigc::connection hcConn; rtengine::ProcEvent EvPrShrContrast; public: + static const Glib::ustring TOOL_NAME; PrSharpening (); ~PrSharpening () override; diff --git a/rtgui/rawcacorrection.cc b/rtgui/rawcacorrection.cc index 207d535ac..3bcd3d03a 100644 --- a/rtgui/rawcacorrection.cc +++ b/rtgui/rawcacorrection.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -RAWCACorr::RAWCACorr () : FoldableToolPanel(this, "rawcacorrection", M("TP_RAWCACORR_LABEL")) +const Glib::ustring RAWCACorr::TOOL_NAME = "rawcacorrection"; + +RAWCACorr::RAWCACorr () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAWCACORR_LABEL")) { auto m = ProcEventMapper::getInstance(); EvPreProcessCAAutoiterations = m->newEvent(DARKFRAME, "HISTORY_MSG_RAWCACORR_AUTOIT"); diff --git a/rtgui/rawcacorrection.h b/rtgui/rawcacorrection.h index 3c95602a7..88b65528e 100644 --- a/rtgui/rawcacorrection.h +++ b/rtgui/rawcacorrection.h @@ -43,6 +43,7 @@ protected: rtengine::ProcEvent EvPreProcessCAColourshiftHistory; public: + static const Glib::ustring TOOL_NAME; RAWCACorr (); diff --git a/rtgui/rawexposure.cc b/rtgui/rawexposure.cc index 7b5ecabc9..778283b75 100644 --- a/rtgui/rawexposure.cc +++ b/rtgui/rawexposure.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -RAWExposure::RAWExposure () : FoldableToolPanel(this, "rawexposure", M("TP_EXPOS_WHITEPOINT_LABEL")) +const Glib::ustring RAWExposure::TOOL_NAME = "rawexposure"; + +RAWExposure::RAWExposure () : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOS_WHITEPOINT_LABEL")) { PexPos = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_LINEAR"), 0.1, 16.0, 0.01, 1)); PexPos->setAdjusterListener (this); diff --git a/rtgui/rawexposure.h b/rtgui/rawexposure.h index 33c897113..ca839d230 100644 --- a/rtgui/rawexposure.h +++ b/rtgui/rawexposure.h @@ -33,6 +33,7 @@ protected: Adjuster* PexPos; public: + static const Glib::ustring TOOL_NAME; RAWExposure (); diff --git a/rtgui/resize.cc b/rtgui/resize.cc index 0bbb65845..de9f6b4d1 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), false, true), maxw(100000), maxh(100000) +const Glib::ustring Resize::TOOL_NAME = "resize"; + +Resize::Resize () : FoldableToolPanel(this, TOOL_NAME, M("TP_RESIZE_LABEL"), false, true), maxw(100000), maxh(100000) { auto m = ProcEventMapper::getInstance(); EvResizeAllowUpscaling = m->newEvent(RESIZE, "HISTORY_MSG_RESIZE_ALLOWUPSCALING"); @@ -170,10 +172,8 @@ Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), fals method->signal_changed().connect ( sigc::mem_fun(*this, &Resize::methodChanged) ); sconn = spec->signal_changed().connect ( sigc::mem_fun(*this, &Resize::specChanged) ); - packBox = Gtk::manage (new ToolParamBlock ()); - pack_end (*packBox); - packBox->hide(); - packBox->set_tooltip_markup (M("TP_PRSHARPENING_TOOLTIP")); + getSubToolsContainer()->hide(); + getSubToolsContainer()->set_tooltip_markup (M("TP_PRSHARPENING_TOOLTIP")); show_all(); } @@ -396,9 +396,9 @@ void Resize::methodChanged () // Post-resize Sharpening assumes the image is in Lab space, and currently Lanczos is the only method which uses that space, and Lanczos is on row 0. if (method->get_active_row_number() == 0) { - packBox->set_sensitive(true); + getSubToolsContainer()->set_sensitive(true); } else { - packBox->set_sensitive(false); + getSubToolsContainer()->set_sensitive(false); } } diff --git a/rtgui/resize.h b/rtgui/resize.h index d13bf8aa4..674bbb34f 100644 --- a/rtgui/resize.h +++ b/rtgui/resize.h @@ -32,14 +32,11 @@ class Resize final : public rtengine::SizeListener { public: + static const Glib::ustring TOOL_NAME; + Resize (); ~Resize () override; - Gtk::Box* getPackBox () - { - return packBox; - } - 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; @@ -87,7 +84,6 @@ private: int cropw, croph; sigc::connection sconn, aconn, wconn, hconn, leconn, seconn; bool wDirty, hDirty, leDirty, seDirty; - ToolParamBlock* packBox; IdleRegister idle_register; static constexpr int MAX_SCALE = 16; // 16 to match the main preview max scale of 1600% diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index e209f5899..11bcc74fb 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -14,7 +14,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL"), false, true), lastmedianmap (false) +const Glib::ustring Retinex::TOOL_NAME = "retinex"; + +Retinex::Retinex () : FoldableToolPanel (this, TOOL_NAME, M ("TP_RETINEX_LABEL"), false, true), lastmedianmap (false) { CurveListener::setMulti (true); std::vector milestones; diff --git a/rtgui/retinex.h b/rtgui/retinex.h index bf480c9cc..bdcbcc466 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -109,6 +109,8 @@ protected: sigc::connection medianmapConn; public: + static const Glib::ustring TOOL_NAME; + Retinex(); ~Retinex() override; diff --git a/rtgui/rgbcurves.cc b/rtgui/rgbcurves.cc index 5e7616e70..0dd6805fe 100644 --- a/rtgui/rgbcurves.cc +++ b/rtgui/rgbcurves.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -RGBCurves::RGBCurves () : FoldableToolPanel(this, "rgbcurves", M("TP_RGBCURVES_LABEL"), false, true), lastLumamode(false) +const Glib::ustring RGBCurves::TOOL_NAME = "rgbcurves"; + +RGBCurves::RGBCurves () : FoldableToolPanel(this, TOOL_NAME, M("TP_RGBCURVES_LABEL"), false, true), lastLumamode(false) { lumamode = Gtk::manage (new Gtk::CheckButton (M("TP_RGBCURVES_LUMAMODE"))); diff --git a/rtgui/rgbcurves.h b/rtgui/rgbcurves.h index edc80eb41..d7e3c3853 100644 --- a/rtgui/rgbcurves.h +++ b/rtgui/rgbcurves.h @@ -45,6 +45,7 @@ protected: sigc::connection lumamodeConn; public: + static const Glib::ustring TOOL_NAME; RGBCurves (); ~RGBCurves () override; diff --git a/rtgui/rotate.cc b/rtgui/rotate.cc index a2456a681..81dd9267c 100644 --- a/rtgui/rotate.cc +++ b/rtgui/rotate.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Rotate::Rotate () : FoldableToolPanel(this, "rotate", M("TP_ROTATE_LABEL")) +const Glib::ustring Rotate::TOOL_NAME = "rotate"; + +Rotate::Rotate () : FoldableToolPanel(this, TOOL_NAME, M("TP_ROTATE_LABEL")) { rlistener = nullptr; diff --git a/rtgui/rotate.h b/rtgui/rotate.h index 41e10eb4d..26db33ffd 100644 --- a/rtgui/rotate.h +++ b/rtgui/rotate.h @@ -36,6 +36,7 @@ protected: LensGeomListener* rlistener; public: + static const Glib::ustring TOOL_NAME; Rotate (); diff --git a/rtgui/rtappchooserdialog.cc b/rtgui/rtappchooserdialog.cc new file mode 100644 index 000000000..50a71ee38 --- /dev/null +++ b/rtgui/rtappchooserdialog.cc @@ -0,0 +1,77 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 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 "rtappchooserdialog.h" + +#if !(defined WIN32 || defined __APPLE__) +#define GTKMM_APPCHOOSERDIALOG +#endif + +RTAppChooserDialog::~RTAppChooserDialog() {} + +#ifdef GTKMM_APPCHOOSERDIALOG // Use Gtk::AppChooserDialog directly. + +RTAppChooserDialog::RTAppChooserDialog(const Glib::ustring &content_type) : + Gtk::AppChooserDialog(content_type) +{ +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() +{ + return Gtk::AppChooserDialog::get_app_info(); +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() const +{ + return Gtk::AppChooserDialog::get_app_info(); +} + +#else // Work around bugs with GLib and glibmm. + +RTAppChooserDialog::RTAppChooserDialog(const Glib::ustring &content_type) : + Gtk::AppChooserDialog(content_type) +{ + // GTK calls a faulty GLib function to update the most recently selected + // application after an application is selected. This removes all signal + // handlers to prevent the function call. + auto signal_id = g_signal_lookup("response", GTK_TYPE_APP_CHOOSER_DIALOG); + while (true) { + auto handler_id = g_signal_handler_find(gobj(), G_SIGNAL_MATCH_ID, signal_id, GQuark(), nullptr, nullptr, nullptr); + if (!handler_id) { + break; + } + g_signal_handler_disconnect(gobj(), handler_id); + } +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() +{ + // glibmm wrapping of GAppInfo does not work on some platforms. Manually + // wrap it here. + GAppInfo *gAppInfo = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(gobj())); + return Glib::wrap(gAppInfo, true); +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() const +{ + GAppInfo *gAppInfo = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER( + const_cast(gobj()))); + return Glib::wrap(gAppInfo, true); +} + +#endif diff --git a/rtgui/rtappchooserdialog.h b/rtgui/rtappchooserdialog.h new file mode 100644 index 000000000..9d0e3b041 --- /dev/null +++ b/rtgui/rtappchooserdialog.h @@ -0,0 +1,39 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 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 +#include +#include + +/** + * Custom version of gtkmm's Gtk::AppChooserDialog to work around crashes + * (https://gitlab.gnome.org/GNOME/glib/-/issues/1104 and + * https://gitlab.gnome.org/GNOME/glibmm/-/issues/94). + */ +class RTAppChooserDialog : public Gtk::AppChooserDialog +{ +public: + RTAppChooserDialog(const Glib::ustring &content_type); + ~RTAppChooserDialog(); + + Glib::RefPtr get_app_info(); + Glib::RefPtr get_app_info() const; +}; diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index fcef8101e..81cbdf9d5 100755 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -1056,6 +1056,13 @@ void RTWindow::MoveFileBrowserToEditor() } } +void RTWindow::updateExternalEditorWidget(int selectedIndex, const std::vector & editors) +{ + if (epanel) { + epanel->updateExternalEditorWidget(selectedIndex, editors); + } +} + void RTWindow::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC) { if (epanel) { @@ -1112,6 +1119,27 @@ void RTWindow::updateHistogramPosition (int oldPosition, int newPosition) } } +void RTWindow::updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools) +{ + if (fpanel) { + fpanel->updateToolPanelToolLocations(favorites, cloneFavoriteTools); + } + + if (epanel) { + epanel->updateToolPanelToolLocations(favorites, cloneFavoriteTools); + } + + for (const auto &panel : epanels) { + panel.second->updateToolPanelToolLocations(favorites, cloneFavoriteTools); + } + + if (options.multiDisplayMode > 0) { + EditWindow::getInstance(this) + ->updateToolPanelToolLocations(favorites, cloneFavoriteTools); + } +} + bool RTWindow::splashClosed (GdkEventAny* event) { delete splash; diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index 0c1cd2572..922588a19 100755 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -33,6 +33,7 @@ class BatchQueueEntry; class BatchQueuePanel; class EditorPanel; +struct ExternalEditor; class FilePanel; class PLDBridge; class RTWindow final : @@ -118,12 +119,15 @@ public: void MoveFileBrowserToEditor(); void MoveFileBrowserToMain(); + void updateExternalEditorWidget(int selectedIndex, const std::vector &editors); void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC); void updateTPVScrollbar (bool hide); void updateHistogramPosition (int oldPosition, int newPosition); void updateFBQueryTB (bool singleRow); void updateFBToolBarVisibility (bool showFilmStripToolBar); void updateShowtooltipVisibility (bool showtooltip); + void updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); bool getIsFullscreen() { return is_fullscreen; diff --git a/rtgui/saveformatpanel.cc b/rtgui/saveformatpanel.cc index 00f6e7b2b..d9b04e8fe 100644 --- a/rtgui/saveformatpanel.cc +++ b/rtgui/saveformatpanel.cc @@ -71,7 +71,7 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr) jpegOpts->set_row_spacing(5); setExpandAlignProperties(jpegOpts, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - jpegQual = new Adjuster (M("SAVEDLG_JPEGQUAL"), 0, 100, 1, 100); + jpegQual = Gtk::manage (new Adjuster (M("SAVEDLG_JPEGQUAL"), 0, 100, 1, 100) ); setExpandAlignProperties(jpegQual, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); jpegQual->setAdjusterListener (this); @@ -95,11 +95,16 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr) // --------------------- TIFF OPTIONS - tiffUncompressed = new Gtk::CheckButton (M("SAVEDLG_TIFFUNCOMPRESSED")); + tiffUncompressed = Gtk::manage (new Gtk::CheckButton (M("SAVEDLG_TIFFUNCOMPRESSED")) ); setExpandAlignProperties(tiffUncompressed, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); tiffUncompressed->signal_toggled().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged)); tiffUncompressed->show_all(); + bigTiff = Gtk::manage (new Gtk::CheckButton (M("SAVEDLG_BIGTIFF")) ); + setExpandAlignProperties(bigTiff, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + bigTiff->signal_toggled().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged)); + bigTiff->show_all(); + // --------------------- MAIN BOX @@ -114,13 +119,11 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr) attach (*hb1, 0, 0, 1, 1); attach (*jpegOpts, 0, 1, 1, 1); attach (*tiffUncompressed, 0, 2, 1, 1); + attach (*bigTiff, 0, 3, 1, 1); attach (*savesPP, 0, 4, 1, 2); } -SaveFormatPanel::~SaveFormatPanel () -{ - delete jpegQual; - delete tiffUncompressed; -} + +SaveFormatPanel::~SaveFormatPanel () = default; void SaveFormatPanel::init (SaveFormat &sf) { @@ -158,6 +161,7 @@ void SaveFormatPanel::init (SaveFormat &sf) jpegQual->setValue(sf.jpegQuality); savesPP->set_active(sf.saveParams); tiffUncompressed->set_active(sf.tiffUncompressed); + bigTiff->set_active(sf.bigTiff); listener = tmp; } @@ -175,6 +179,7 @@ SaveFormat SaveFormatPanel::getFormat () sf.jpegQuality = jpegQual->getValue(); sf.jpegSubSamp = jpegSubSamp->get_active_row_number() + 1; sf.tiffUncompressed = tiffUncompressed->get_active(); + sf.bigTiff = bigTiff->get_active(); sf.saveParams = savesPP->get_active(); return sf; @@ -193,12 +198,15 @@ void SaveFormatPanel::formatChanged () if (fr == "jpg") { jpegOpts->show_all(); tiffUncompressed->hide(); + bigTiff->hide(); } else if (fr == "png") { jpegOpts->hide(); tiffUncompressed->hide(); + bigTiff->hide(); } else if (fr == "tif") { jpegOpts->hide(); tiffUncompressed->show_all(); + bigTiff->show_all(); } if (listener) { diff --git a/rtgui/saveformatpanel.h b/rtgui/saveformatpanel.h index af9baa58a..9d9f6266e 100644 --- a/rtgui/saveformatpanel.h +++ b/rtgui/saveformatpanel.h @@ -39,6 +39,7 @@ class SaveFormatPanel : public Gtk::Grid, public AdjusterListener, public rtengi protected: Adjuster* jpegQual; Gtk::CheckButton* tiffUncompressed; + Gtk::CheckButton* bigTiff; MyComboBoxText* format; MyComboBoxText* jpegSubSamp; Gtk::Grid* formatOpts; diff --git a/rtgui/sensorbayer.cc b/rtgui/sensorbayer.cc index 39ed5cb91..70537f666 100644 --- a/rtgui/sensorbayer.cc +++ b/rtgui/sensorbayer.cc @@ -20,11 +20,10 @@ #include "guiutils.h" #include "rtimage.h" -SensorBayer::SensorBayer () : FoldableToolPanel(this, "sensorbayer", M("TP_RAW_SENSOR_BAYER_LABEL")) -{ +const Glib::ustring SensorBayer::TOOL_NAME = "sensorbayer"; - packBox = Gtk::manage (new ToolParamBlock ()); - pack_start (*packBox); +SensorBayer::SensorBayer () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_SENSOR_BAYER_LABEL")) +{ show_all (); } diff --git a/rtgui/sensorbayer.h b/rtgui/sensorbayer.h index 2401bf760..d3d867ace 100644 --- a/rtgui/sensorbayer.h +++ b/rtgui/sensorbayer.h @@ -27,15 +27,8 @@ class SensorBayer final : public FoldableToolPanel { -protected: - ToolParamBlock* packBox; - public: + static const Glib::ustring TOOL_NAME; SensorBayer (); - - Gtk::Box* getPackBox () - { - return packBox; - } }; diff --git a/rtgui/sensorxtrans.cc b/rtgui/sensorxtrans.cc index f13e6607f..45e5d57e4 100644 --- a/rtgui/sensorxtrans.cc +++ b/rtgui/sensorxtrans.cc @@ -20,11 +20,10 @@ #include "guiutils.h" #include "rtimage.h" -SensorXTrans::SensorXTrans () : FoldableToolPanel(this, "sensorxtrans", M("TP_RAW_SENSOR_XTRANS_LABEL")) -{ +const Glib::ustring SensorXTrans::TOOL_NAME = "sensorxtrans"; - packBox = Gtk::manage (new ToolParamBlock ()); - pack_start (*packBox); +SensorXTrans::SensorXTrans () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_SENSOR_XTRANS_LABEL")) +{ show_all (); } diff --git a/rtgui/sensorxtrans.h b/rtgui/sensorxtrans.h index eee014f6c..2e5c10483 100644 --- a/rtgui/sensorxtrans.h +++ b/rtgui/sensorxtrans.h @@ -27,15 +27,8 @@ class SensorXTrans final: public FoldableToolPanel { -protected: - ToolParamBlock* packBox; - public: + static const Glib::ustring TOOL_NAME; SensorXTrans (); - - Gtk::Box* getPackBox () - { - return packBox; - } }; diff --git a/rtgui/shadowshighlights.cc b/rtgui/shadowshighlights.cc index a168527d6..3c821d863 100644 --- a/rtgui/shadowshighlights.cc +++ b/rtgui/shadowshighlights.cc @@ -25,7 +25,9 @@ using namespace rtengine; using namespace rtengine::procparams; -ShadowsHighlights::ShadowsHighlights () : FoldableToolPanel(this, "shadowshighlights", M("TP_SHADOWSHLIGHTS_LABEL"), false, true) +const Glib::ustring ShadowsHighlights::TOOL_NAME = "shadowshighlights"; + +ShadowsHighlights::ShadowsHighlights () : FoldableToolPanel(this, TOOL_NAME, M("TP_SHADOWSHLIGHTS_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); EvSHColorspace = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_SH_COLORSPACE"); diff --git a/rtgui/shadowshighlights.h b/rtgui/shadowshighlights.h index 7bb0bb01c..fd8b30a6a 100644 --- a/rtgui/shadowshighlights.h +++ b/rtgui/shadowshighlights.h @@ -40,6 +40,7 @@ protected: rtengine::ProcEvent EvSHColorspace; public: + static const Glib::ustring TOOL_NAME; ShadowsHighlights (); diff --git a/rtgui/sharpenedge.cc b/rtgui/sharpenedge.cc index e00d919c3..247a8a5d7 100644 --- a/rtgui/sharpenedge.cc +++ b/rtgui/sharpenedge.cc @@ -28,8 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring SharpenEdge::TOOL_NAME = "sharpenedge"; -SharpenEdge::SharpenEdge () : FoldableToolPanel(this, "sharpenedge", M("TP_SHARPENEDGE_LABEL"), true, true) +SharpenEdge::SharpenEdge () : FoldableToolPanel(this, TOOL_NAME, M("TP_SHARPENEDGE_LABEL"), true, true) { passes = Gtk::manage(new Adjuster (M("TP_SHARPENEDGE_PASSES"), 1, 4, 1, 2)); diff --git a/rtgui/sharpenedge.h b/rtgui/sharpenedge.h index a813d86e1..bfb48b408 100644 --- a/rtgui/sharpenedge.h +++ b/rtgui/sharpenedge.h @@ -44,6 +44,7 @@ protected: bool lastchanthree; public: + static const Glib::ustring TOOL_NAME; SharpenEdge (); diff --git a/rtgui/sharpening.cc b/rtgui/sharpening.cc index 687358349..ba39ac97c 100644 --- a/rtgui/sharpening.cc +++ b/rtgui/sharpening.cc @@ -23,7 +23,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Sharpening::Sharpening () : FoldableToolPanel(this, "sharpening", M("TP_SHARPENING_LABEL"), true, true) +const Glib::ustring Sharpening::TOOL_NAME = "sharpening"; + +Sharpening::Sharpening () : FoldableToolPanel(this, TOOL_NAME, M("TP_SHARPENING_LABEL"), true, true) { auto m = ProcEventMapper::getInstance(); EvSharpenContrast = m->newEvent(SHARPENING, "HISTORY_MSG_SHARPENING_CONTRAST"); diff --git a/rtgui/sharpening.h b/rtgui/sharpening.h index aa65b3662..e30db3dd2 100644 --- a/rtgui/sharpening.h +++ b/rtgui/sharpening.h @@ -62,6 +62,7 @@ protected: rtengine::ProcEvent EvSharpenContrast; rtengine::ProcEvent EvSharpenBlur; public: + static const Glib::ustring TOOL_NAME; Sharpening (); ~Sharpening () override; diff --git a/rtgui/sharpenmicro.cc b/rtgui/sharpenmicro.cc index 78228d27c..527d146d7 100644 --- a/rtgui/sharpenmicro.cc +++ b/rtgui/sharpenmicro.cc @@ -29,8 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring SharpenMicro::TOOL_NAME = "sharpenmicro"; -SharpenMicro::SharpenMicro () : FoldableToolPanel(this, "sharpenmicro", M("TP_SHARPENMICRO_LABEL"), true, true) +SharpenMicro::SharpenMicro () : FoldableToolPanel(this, TOOL_NAME, M("TP_SHARPENMICRO_LABEL"), true, true) { auto m = ProcEventMapper::getInstance(); diff --git a/rtgui/sharpenmicro.h b/rtgui/sharpenmicro.h index 23224dd60..876117e68 100644 --- a/rtgui/sharpenmicro.h +++ b/rtgui/sharpenmicro.h @@ -47,6 +47,7 @@ protected: bool lastmatrix; public: + static const Glib::ustring TOOL_NAME; SharpenMicro (); diff --git a/rtgui/softlight.cc b/rtgui/softlight.cc index 84461f169..3a7f84985 100644 --- a/rtgui/softlight.cc +++ b/rtgui/softlight.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -SoftLight::SoftLight(): FoldableToolPanel(this, "softlight", M("TP_SOFTLIGHT_LABEL"), false, true) +const Glib::ustring SoftLight::TOOL_NAME = "softlight"; + +SoftLight::SoftLight(): FoldableToolPanel(this, TOOL_NAME, M("TP_SOFTLIGHT_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); EvSoftLightEnabled = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_SOFTLIGHT_ENABLED"); diff --git a/rtgui/softlight.h b/rtgui/softlight.h index 710da4e34..3b9ff5399 100644 --- a/rtgui/softlight.h +++ b/rtgui/softlight.h @@ -32,6 +32,7 @@ private: rtengine::ProcEvent EvSoftLightStrength; public: + static const Glib::ustring TOOL_NAME; SoftLight(); diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 34e2f0c18..43fdb632d 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -52,8 +52,10 @@ enum GeometryIndex { } +const Glib::ustring Spot::TOOL_NAME = "spot"; + Spot::Spot() : - FoldableToolPanel(this, "spot", M ("TP_SPOT_LABEL"), true, true), + FoldableToolPanel(this, TOOL_NAME, M ("TP_SPOT_LABEL"), true, true), EditSubscriber(ET_OBJECTS), draggedSide(DraggedSide::NONE), lastObject(-1), diff --git a/rtgui/spot.h b/rtgui/spot.h index 7cdea35f7..236cd36ad 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -99,6 +99,7 @@ protected: Geometry* getVisibleGeometryFromMO (int MOID); public: + static const Glib::ustring TOOL_NAME; Spot (); ~Spot (); diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc index 29222992e..e00e3c1b0 100644 --- a/rtgui/thumbbrowserbase.cc +++ b/rtgui/thumbbrowserbase.cc @@ -1091,6 +1091,25 @@ bool ThumbBrowserBase::Internal::on_scroll_event (GdkEventScroll* event) } +void ThumbBrowserBase::resort () +{ + { + MYWRITERLOCK(l, entryRW); + + std::sort( + fd.begin(), + fd.end(), + [](const ThumbBrowserEntryBase* a, const ThumbBrowserEntryBase* b) + { + bool lt = a->compare(*b, options.sortMethod); + return options.sortDescending ? !lt : lt; + } + ); + } + + redraw (); +} + void ThumbBrowserBase::redraw (ThumbBrowserEntryBase* entry) { @@ -1218,9 +1237,30 @@ void ThumbBrowserBase::enableTabMode(bool enable) } } -void ThumbBrowserBase::initEntry (ThumbBrowserEntryBase* entry) +void ThumbBrowserBase::insertEntry (ThumbBrowserEntryBase* entry) { - entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + // find place in sort order + { + MYWRITERLOCK(l, entryRW); + + fd.insert( + std::lower_bound( + fd.begin(), + fd.end(), + entry, + [](const ThumbBrowserEntryBase* a, const ThumbBrowserEntryBase* b) + { + bool lt = a->compare(*b, options.sortMethod); + return options.sortDescending ? !lt : lt; + } + ), + entry + ); + + entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + } + + redraw (); } void ThumbBrowserBase::getScrollPosition (double& h, double& v) diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h index 2d41cdfab..8c1ec49c8 100644 --- a/rtgui/thumbbrowserbase.h +++ b/rtgui/thumbbrowserbase.h @@ -208,12 +208,13 @@ public: return fd; } void on_style_updated () override; + void resort (); // re-apply sort method void redraw (ThumbBrowserEntryBase* entry = nullptr); // arrange files and draw area void refreshThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw void refreshQuickThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw void refreshEditedState (const std::set& efiles); - void initEntry (ThumbBrowserEntryBase* entry); + void insertEntry (ThumbBrowserEntryBase* entry); void getScrollPosition (double& h, double& v); void setScrollPosition (double h, double v); diff --git a/rtgui/thumbbrowserentrybase.cc b/rtgui/thumbbrowserentrybase.cc index 2b5c102e3..424b04680 100644 --- a/rtgui/thumbbrowserentrybase.cc +++ b/rtgui/thumbbrowserentrybase.cc @@ -120,7 +120,7 @@ Glib::ustring getPaddedName(const Glib::ustring& name) } -ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) : +ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname, Thumbnail *thm) : fnlabw(0), fnlabh(0), dtlabw(0), @@ -154,7 +154,8 @@ ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) : bbPreview(nullptr), cursor_type(CSUndefined), collate_name(getPaddedName(dispname).casefold_collate_key()), - thumbnail(nullptr), + collate_exif(getPaddedName(thm->getExifString()).casefold_collate_key()), + thumbnail(thm), filename(fname), selected(false), drawable(false), diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h index fa3e8f0f3..41d33382d 100644 --- a/rtgui/thumbbrowserentrybase.h +++ b/rtgui/thumbbrowserentrybase.h @@ -26,6 +26,8 @@ #include "guiutils.h" #include "lwbuttonset.h" #include "threadutils.h" +#include "options.h" +#include "thumbnail.h" #include "../rtengine/coord2d.h" @@ -96,6 +98,7 @@ protected: private: const std::string collate_name; + const std::string collate_exif; public: @@ -118,7 +121,7 @@ public: bool updatepriority; eWithFilename withFilename; - explicit ThumbBrowserEntryBase (const Glib::ustring& fname); + explicit ThumbBrowserEntryBase (const Glib::ustring& fname, Thumbnail *thm); virtual ~ThumbBrowserEntryBase (); void setParent (ThumbBrowserBase* l) @@ -175,9 +178,32 @@ public: void setPosition (int x, int y, int w, int h); void setOffset (int x, int y); - bool operator <(const ThumbBrowserEntryBase& other) const + bool compare (const ThumbBrowserEntryBase& other, Options::SortMethod method) const { - return collate_name < other.collate_name; + int cmp = 0; + switch (method){ + case Options::SORT_BY_NAME: + return collate_name < other.collate_name; + case Options::SORT_BY_DATE: + cmp = thumbnail->getDateTime().compare(other.thumbnail->getDateTime()); + break; + case Options::SORT_BY_EXIF: + cmp = collate_exif.compare(other.collate_exif); + break; + case Options::SORT_BY_RANK: + cmp = thumbnail->getRank() - other.thumbnail->getRank(); + break; + case Options::SORT_BY_LABEL: + cmp = thumbnail->getColorLabel() - other.thumbnail->getColorLabel(); + break; + case Options::SORT_METHOD_COUNT: abort(); + } + + // Always fall back to sorting by name + if (!cmp) + cmp = collate_name.compare(other.collate_name); + + return cmp < 0; } virtual void refreshThumbnailImage () = 0; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index cc8e9ad81..30766ebc9 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -31,6 +31,7 @@ #include "../rtengine/procparams.h" #include "../rtengine/rtthumbnail.h" #include +#include #include "../rtengine/dynamicprofile.h" #include "../rtengine/profilestore.h" @@ -266,7 +267,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu // Should we ask all frame's MetaData ? imageMetaData = rtengine::FramesMetaData::fromFile (fname, nullptr, true); } - PartialProfile *pp = ProfileStore::getInstance()->loadDynamicProfile(imageMetaData); + PartialProfile *pp = ProfileStore::getInstance()->loadDynamicProfile(imageMetaData, fname); delete imageMetaData; int err = pp->pparams->save(outFName); pp->deleteInstance(); @@ -718,11 +719,44 @@ rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::Pro void Thumbnail::generateExifDateTimeStrings () { + if (cfs.timeValid) { + std::string dateFormat = options.dateFormat; + std::ostringstream ostr; + bool spec = false; - exifString = ""; - dateTimeString = ""; + for (size_t i = 0; i < dateFormat.size(); i++) + if (spec && dateFormat[i] == 'y') { + ostr << cfs.year; + spec = false; + } else if (spec && dateFormat[i] == 'm') { + ostr << (int)cfs.month; + spec = false; + } else if (spec && dateFormat[i] == 'd') { + ostr << (int)cfs.day; + spec = false; + } else if (dateFormat[i] == '%') { + spec = true; + } else { + ostr << (char)dateFormat[i]; + spec = false; + } + + ostr << " " << (int)cfs.hour; + ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.min; + ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.sec; + + dateTimeString = ostr.str (); + dateTime = Glib::DateTime::create_local(cfs.year, cfs.month, cfs.day, + cfs.hour, cfs.min, cfs.sec); + } + + if (!dateTime.gobj() || !cfs.timeValid) { + dateTimeString = ""; + dateTime = Glib::DateTime::create_now_utc(0); + } if (!cfs.exifValid) { + exifString = ""; return; } @@ -731,33 +765,6 @@ void Thumbnail::generateExifDateTimeStrings () if (options.fbShowExpComp && cfs.expcomp != "0.00" && !cfs.expcomp.empty()) { // don't show exposure compensation if it is 0.00EV;old cache files do not have ExpComp, so value will not be displayed. exifString = Glib::ustring::compose ("%1 %2EV", exifString, cfs.expcomp); // append exposure compensation to exifString } - - std::string dateFormat = options.dateFormat; - std::ostringstream ostr; - bool spec = false; - - for (size_t i = 0; i < dateFormat.size(); i++) - if (spec && dateFormat[i] == 'y') { - ostr << cfs.year; - spec = false; - } else if (spec && dateFormat[i] == 'm') { - ostr << (int)cfs.month; - spec = false; - } else if (spec && dateFormat[i] == 'd') { - ostr << (int)cfs.day; - spec = false; - } else if (dateFormat[i] == '%') { - spec = true; - } else { - ostr << (char)dateFormat[i]; - spec = false; - } - - ostr << " " << (int)cfs.hour; - ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.min; - ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.sec; - - dateTimeString = ostr.str (); } const Glib::ustring& Thumbnail::getExifString () const @@ -772,6 +779,12 @@ const Glib::ustring& Thumbnail::getDateTimeString () const return dateTimeString; } +const Glib::DateTime& Thumbnail::getDateTime () const +{ + + return dateTime; +} + void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tempBias) { if (cfs.redAWBMul != -1.0) { @@ -802,6 +815,16 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname, std::unique_ptrgetDateTimeAsTS() > 0) { + cfs.year = 1900 + idata->getDateTime().tm_year; + cfs.month = idata->getDateTime().tm_mon + 1; + cfs.day = idata->getDateTime().tm_mday; + cfs.hour = idata->getDateTime().tm_hour; + cfs.min = idata->getDateTime().tm_min; + cfs.sec = idata->getDateTime().tm_sec; + cfs.timeValid = true; + } + if (idata->hasExif()) { cfs.shutter = idata->getShutterSpeed (); cfs.fnumber = idata->getFNumber (); @@ -814,18 +837,11 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname, std::unique_ptrgetPixelShift (); cfs.frameCount = idata->getFrameCount (); cfs.sampleFormat = idata->getSampleFormat (); - cfs.year = 1900 + idata->getDateTime().tm_year; - cfs.month = idata->getDateTime().tm_mon + 1; - cfs.day = idata->getDateTime().tm_mday; - cfs.hour = idata->getDateTime().tm_hour; - cfs.min = idata->getDateTime().tm_min; - cfs.sec = idata->getDateTime().tm_sec; - cfs.timeValid = true; - cfs.exifValid = true; cfs.lens = idata->getLens(); cfs.camMake = idata->getMake(); cfs.camModel = idata->getModel(); cfs.rating = idata->getRating(); + cfs.exifValid = true; if (idata->getOrientation() == "Rotate 90 CW") { deg = 90; diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index cda69f030..491151028 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -22,6 +22,7 @@ #include #include +#include #include "cacheimagedata.h" #include "threadutils.h" @@ -73,6 +74,7 @@ class Thumbnail // exif & date/time strings Glib::ustring exifString; Glib::ustring dateTimeString; + Glib::DateTime dateTime; bool initial_; @@ -124,6 +126,7 @@ public: const Glib::ustring& getExifString () const; const Glib::ustring& getDateTimeString () const; + const Glib::DateTime& getDateTime () const; void getCamWB (double& temp, double& green) const; void getAutoWB (double& temp, double& green, double equal, double tempBias); void getSpotWB (int x, int y, int rect, double& temp, double& green); diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index 6cbd70825..bf81c6f22 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -33,13 +33,16 @@ using namespace rtengine; using namespace rtengine::procparams; -ToneCurve::ToneCurve() : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LABEL")) +const Glib::ustring ToneCurve::TOOL_NAME = "tonecurve"; + +ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL")) { auto m = ProcEventMapper::getInstance(); EvHistMatching = m->newEvent(AUTOEXP, "HISTORY_MSG_HISTMATCHING"); EvHistMatchingBatch = m->newEvent(M_VOID, "HISTORY_MSG_HISTMATCHING"); EvClampOOG = m->newEvent(DARKFRAME, "HISTORY_MSG_CLAMPOOG"); EvHLbl = m->newEvent(DEMOSAIC, "HISTORY_MSG_HLBL"); + EvHLth = m->newEvent(DEMOSAIC, "HISTORY_MSG_HLTH"); CurveListener::setMulti(true); @@ -95,13 +98,14 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LAB method = Gtk::manage (new MyComboBoxText ()); method->append (M("TP_HLREC_LUMINANCE")); method->append (M("TP_HLREC_CIELAB")); - method->append (M("TP_HLREC_COLOR")); method->append (M("TP_HLREC_BLEND")); + method->append (M("TP_HLREC_COLOR")); + method->append (M("TP_HLREC_COLOROPP")); Gtk::Box *hrVBox; hrVBox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); hrVBox->set_spacing(2); - method->set_active(0); + method->set_active(4); Gtk::Frame* const hrFrame = Gtk::manage(new Gtk::Frame()); hrFrame->set_label_align(0.025, 0.5); hrFrame->set_label_widget(*hrenabled); @@ -111,9 +115,11 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LAB hlrbox->pack_start (*lab, Gtk::PACK_SHRINK); hlrbox->pack_start (*method); hlbl = Gtk::manage(new Adjuster(M("TP_HLREC_HLBLUR"), 0, 4, 1, 0)); + hlth = Gtk::manage(new Adjuster(M("TP_HLREC_HLTH"), 0.25, 1.75, 0.01, 1.)); hrVBox->pack_start(*hlrbox, Gtk::PACK_SHRINK); hrVBox->pack_start(*hlbl); + hrVBox->pack_start(*hlth); hrFrame->add(*hrVBox); pack_start(*hrFrame); @@ -221,6 +227,7 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LAB black->setAdjusterListener(this); hlcompr->setAdjusterListener(this); hlbl->setAdjusterListener(this); + hlth->setAdjusterListener(this); hlcomprthresh->setAdjusterListener(this); shcompr->setAdjusterListener(this); contrast->setAdjusterListener(this); @@ -252,6 +259,7 @@ void ToneCurve::read(const ProcParams* pp, const ParamsEdited* pedited) black->setValue(pp->toneCurve.black); hlcompr->setValue(pp->toneCurve.hlcompr); hlbl->setValue(pp->toneCurve.hlbl); + hlth->setValue(pp->toneCurve.hlth); hlcomprthresh->setValue(pp->toneCurve.hlcomprthresh); shcompr->setValue(pp->toneCurve.shcompr); @@ -281,6 +289,7 @@ void ToneCurve::read(const ProcParams* pp, const ParamsEdited* pedited) black->setEditedState(pedited->toneCurve.black ? Edited : UnEdited); hlcompr->setEditedState(pedited->toneCurve.hlcompr ? Edited : UnEdited); hlbl->setEditedState(pedited->toneCurve.hlbl ? Edited : UnEdited); + hlth->setEditedState(pedited->toneCurve.hlth ? Edited : UnEdited); hlcomprthresh->setEditedState(pedited->toneCurve.hlcomprthresh ? Edited : UnEdited); shcompr->setEditedState(pedited->toneCurve.shcompr ? Edited : UnEdited); brightness->setEditedState(pedited->toneCurve.brightness ? Edited : UnEdited); @@ -308,16 +317,18 @@ void ToneCurve::read(const ProcParams* pp, const ParamsEdited* pedited) hrenabled->set_active(pp->toneCurve.hrenabled); enaconn.block(false); - if (pedited && !pedited->toneCurve.method) { - method->set_active(4); - } else if (pp->toneCurve.method == "Luminance") { + if (pedited && !pedited->toneCurve.method) { + method->set_active(5); + } else if (pp->toneCurve.method == "Luminance") { method->set_active(0); } else if (pp->toneCurve.method == "CIELab blending") { method->set_active(1); - } else if (pp->toneCurve.method == "Color") { - method->set_active(2); } else if (pp->toneCurve.method == "Blend") { + method->set_active(2); + } else if (pp->toneCurve.method == "Color") { method->set_active(3); + } else if (pp->toneCurve.method == "Coloropp") { + method->set_active(4); } hrenabledChanged(); @@ -352,6 +363,7 @@ void ToneCurve::write(ProcParams* pp, ParamsEdited* pedited) pp->toneCurve.black = black->getValue(); pp->toneCurve.hlcompr = hlcompr->getValue(); pp->toneCurve.hlbl = hlbl->getValue(); + pp->toneCurve.hlth = hlth->getValue(); pp->toneCurve.hlcomprthresh = hlcomprthresh->getValue(); pp->toneCurve.shcompr = shcompr->getValue(); pp->toneCurve.brightness = brightness->getValue(); @@ -401,6 +413,7 @@ void ToneCurve::write(ProcParams* pp, ParamsEdited* pedited) pedited->toneCurve.black = black->getEditedState(); pedited->toneCurve.hlcompr = hlcompr->getEditedState(); pedited->toneCurve.hlbl = hlbl->getEditedState(); + pedited->toneCurve.hlth = hlth->getEditedState(); pedited->toneCurve.hlcomprthresh = hlcomprthresh->getEditedState(); pedited->toneCurve.shcompr = shcompr->getEditedState(); pedited->toneCurve.brightness = brightness->getEditedState(); @@ -412,7 +425,7 @@ void ToneCurve::write(ProcParams* pp, ParamsEdited* pedited) pedited->toneCurve.curve2 = !shape2->isUnChanged(); pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 6; pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 6; - pedited->toneCurve.method = method->get_active_row_number() != 4; + pedited->toneCurve.method = method->get_active_row_number() != 5; pedited->toneCurve.hrenabled = !hrenabled->get_inconsistent(); pedited->toneCurve.histmatching = !histmatching->get_inconsistent(); pedited->toneCurve.fromHistMatching = true; @@ -426,9 +439,11 @@ void ToneCurve::write(ProcParams* pp, ParamsEdited* pedited) } else if (method->get_active_row_number() == 1) { pp->toneCurve.method = "CIELab blending"; } else if (method->get_active_row_number() == 2) { - pp->toneCurve.method = "Color"; - } else if (method->get_active_row_number() == 3) { pp->toneCurve.method = "Blend"; + } else if (method->get_active_row_number() == 3) { + pp->toneCurve.method = "Color"; + } else if (method->get_active_row_number() == 4) { + pp->toneCurve.method = "Coloropp"; } } @@ -452,15 +467,21 @@ void ToneCurve::hrenabledChanged() if (hrenabled->get_active()) { hlrbox->show(); hlrbox->set_sensitive(true); - if (method->get_active_row_number() == 2) { + if (method->get_active_row_number() == 3) { hlbl->show(); + hlth->hide(); + } else if (method->get_active_row_number() == 4){ + hlbl->hide(); + hlth->show(); } else { hlbl->hide(); - } + hlth->hide(); + } } else { hlrbox->show(); hlrbox->set_sensitive(false); hlbl->hide(); + hlth->hide(); } } @@ -485,11 +506,16 @@ void ToneCurve::hrenabledChanged() void ToneCurve::methodChanged() { - if (method->get_active_row_number() == 2) { + if (method->get_active_row_number() == 3) { hlbl->show(); - } else { + hlth->hide(); + } else if (method->get_active_row_number() == 4){ hlbl->hide(); - } + hlth->show(); + } else { + hlbl->hide(); + hlth->hide(); + } if (listener) { setHistmatching(false); if (hrenabled->get_active()) { @@ -511,6 +537,7 @@ void ToneCurve::setRaw(bool raw) disableListener(); method->set_sensitive(raw); hlbl->set_sensitive(raw); + hlth->set_sensitive(raw); hrenabled->set_sensitive(raw); histmatching->set_sensitive(raw); enableListener(); @@ -524,6 +551,7 @@ void ToneCurve::setDefaults(const ProcParams* defParams, const ParamsEdited* ped black->setDefault(defParams->toneCurve.black); hlcompr->setDefault(defParams->toneCurve.hlcompr); hlbl->setDefault(defParams->toneCurve.hlbl); + hlth->setDefault(defParams->toneCurve.hlth); hlcomprthresh->setDefault(defParams->toneCurve.hlcomprthresh); shcompr->setDefault(defParams->toneCurve.shcompr); contrast->setDefault(defParams->toneCurve.contrast); @@ -534,6 +562,7 @@ void ToneCurve::setDefaults(const ProcParams* defParams, const ParamsEdited* ped black->setDefaultEditedState(pedited->toneCurve.black ? Edited : UnEdited); hlcompr->setDefaultEditedState(pedited->toneCurve.hlcompr ? Edited : UnEdited); hlbl->setDefaultEditedState(pedited->toneCurve.hlbl ? Edited : UnEdited); + hlth->setDefaultEditedState(pedited->toneCurve.hlth ? Edited : UnEdited); hlcomprthresh->setDefaultEditedState(pedited->toneCurve.hlcomprthresh ? Edited : UnEdited); shcompr->setDefaultEditedState(pedited->toneCurve.shcompr ? Edited : UnEdited); brightness->setDefaultEditedState(pedited->toneCurve.brightness ? Edited : UnEdited); @@ -544,6 +573,7 @@ void ToneCurve::setDefaults(const ProcParams* defParams, const ParamsEdited* ped black->setDefaultEditedState(Irrelevant); hlcompr->setDefaultEditedState(Irrelevant); hlbl->setDefaultEditedState(Irrelevant); + hlth->setDefaultEditedState(Irrelevant); hlcomprthresh->setDefaultEditedState(Irrelevant); shcompr->setDefaultEditedState(Irrelevant); brightness->setDefaultEditedState(Irrelevant); @@ -658,6 +688,8 @@ void ToneCurve::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvSaturation, costr); } else if (a == hlbl) { listener->panelChanged(EvHLbl, costr); + } else if (a == hlth) { + listener->panelChanged(EvHLth, costr); } else if (a == hlcompr) { listener->panelChanged(EvHLCompr, costr); @@ -693,6 +725,7 @@ void ToneCurve::neutral_pressed() expcomp->setValue(0); hlcompr->setValue(0); hlbl->setValue(0); + hlth->setValue(1.0); hlcomprthresh->setValue(0); brightness->setValue(0); black->setValue(0); @@ -705,6 +738,7 @@ void ToneCurve::neutral_pressed() hlrbox->show(); hlrbox->set_sensitive(false); hlbl->hide(); + hlth->hide(); } if (!black->getAddMode() && !batchMode) { @@ -839,6 +873,7 @@ void ToneCurve::waitForAutoExp() hrenabled->set_sensitive(false); method->set_sensitive(false); hlbl->set_sensitive(false); + hlth->set_sensitive(false); histmatching->set_sensitive(false); } @@ -851,6 +886,7 @@ void ToneCurve::enableAll() black->setEnabled(true); hlcompr->setEnabled(true); hlbl->setEnabled(true); + hlth->setEnabled(true); hlcomprthresh->setEnabled(true); shcompr->setEnabled(true); contrast->setEnabled(true); @@ -862,6 +898,7 @@ void ToneCurve::enableAll() hrenabled->set_sensitive(true); method->set_sensitive(true); hlbl->set_sensitive(true); + hlth->set_sensitive(true); histmatching->set_sensitive(true); } @@ -881,6 +918,7 @@ void ToneCurve::setBatchMode(bool batchMode) black->showEditedCB(); hlcompr->showEditedCB(); hlbl->showEditedCB(); + hlth->showEditedCB(); hlcomprthresh->showEditedCB(); shcompr->showEditedCB(); brightness->showEditedCB(); @@ -994,16 +1032,22 @@ void ToneCurve::autoExpChanged(double expcomp, int bright, int contr, int black, if (nextHLRecons) { hlrbox->show(); hlrbox->set_sensitive(true); - if (method->get_active_row_number() == 2) { + if (method->get_active_row_number() == 3) { hlbl->show(); - } else { + hlth->hide(); + } else if (method->get_active_row_number() == 4){ hlbl->hide(); - } + hlth->show(); + } else { + hlbl->hide(); + hlth->hide(); + } } else if (!batchMode) { hlrbox->show(); hlrbox->set_sensitive(false); hlbl->hide(); - } + hlth->hide(); + } if (!this->black->getAddMode() && !batchMode) { shcompr->set_sensitive(static_cast(this->black->getValue())); //at black=0 shcompr value has no effect diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h index 6dd77951d..7f0f1ef69 100644 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -48,6 +48,7 @@ protected: sigc::connection enaconn; bool lasthrEnabled; Adjuster* hlbl; + Adjuster* hlth; Gtk::Box* abox; Gtk::Box* hlrbox; @@ -82,6 +83,7 @@ protected: rtengine::ProcEvent EvHistMatchingBatch; rtengine::ProcEvent EvClampOOG; rtengine::ProcEvent EvHLbl; + rtengine::ProcEvent EvHLth; // used temporarily in eventing double nextExpcomp; @@ -97,6 +99,8 @@ protected: void setHistmatching(bool enabled); public: + static const Glib::ustring TOOL_NAME; + ToneCurve (); ~ToneCurve () override; diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc new file mode 100644 index 000000000..cf25dbc34 --- /dev/null +++ b/rtgui/toollocationpref.cc @@ -0,0 +1,760 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 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 + +#include "guiutils.h" +#include "options.h" +#include "rtimage.h" +#include "rtscalable.h" +#include "toollocationpref.h" +#include "toolpanelcoord.h" + +using Tool = ToolPanelCoordinator::Tool; +using Favorites = std::unordered_set; + +namespace +{ + +/** + * Returns the language key for the panel's title. + */ +Glib::ustring getToolPanelTitleKey(ToolPanelCoordinator::Panel panel) +{ + switch (panel) { + case ToolPanelCoordinator::Panel::FAVORITE: + return "MAIN_TAB_FAVORITES"; + case ToolPanelCoordinator::Panel::EXPOSURE: + return "MAIN_TAB_EXPOSURE"; + case ToolPanelCoordinator::Panel::DETAILS: + return "MAIN_TAB_DETAIL"; + case ToolPanelCoordinator::Panel::COLOR: + return "MAIN_TAB_COLOR"; + case ToolPanelCoordinator::Panel::ADVANCED: + return "MAIN_TAB_ADVANCED"; + case ToolPanelCoordinator::Panel::LOCALLAB: + return "MAIN_TAB_LOCALLAB"; + case ToolPanelCoordinator::Panel::TRANSFORM_PANEL: + return "MAIN_TAB_TRANSFORM"; + case ToolPanelCoordinator::Panel::RAW: + return "MAIN_TAB_RAW"; + } + assert(false); + return ""; +} + +/** + * Returns the language key for the tool's title. + */ +Glib::ustring getToolTitleKey(Tool tool) +{ + using Tool = Tool; + switch (tool) { + case Tool::TONE_CURVE: + return "TP_EXPOSURE_LABEL"; + case Tool::SHADOWS_HIGHLIGHTS: + return "TP_SHADOWSHLIGHTS_LABEL"; + case Tool::IMPULSE_DENOISE: + return "TP_IMPULSEDENOISE_LABEL"; + case Tool::DEFRINGE_TOOL: + return "TP_DEFRINGE_LABEL"; + case Tool::SPOT: + return "TP_SPOT_LABEL"; + case Tool::DIR_PYR_DENOISE: + return "TP_DIRPYRDENOISE_LABEL"; + case Tool::EPD: + return "TP_EPD_LABEL"; + case Tool::SHARPENING_TOOL: + return "TP_SHARPENING_LABEL"; + case Tool::LOCAL_CONTRAST: + return "TP_LOCALCONTRAST_LABEL"; + case Tool::SHARPEN_EDGE: + return "TP_SHARPENEDGE_LABEL"; + case Tool::SHARPEN_MICRO: + return "TP_SHARPENMICRO_LABEL"; + case Tool::L_CURVE: + return "TP_LABCURVE_LABEL"; + case Tool::RGB_CURVES: + return "TP_RGBCURVES_LABEL"; + case Tool::COLOR_TONING: + return "TP_COLORTONING_LABEL"; + case Tool::LENS_GEOM: + return "TP_LENSGEOM_LABEL"; + case Tool::LENS_PROF: + return "TP_LENSPROFILE_LABEL"; + case Tool::DISTORTION: + return "TP_DISTORTION_LABEL"; + case Tool::ROTATE: + return "TP_ROTATE_LABEL"; + case Tool::VIBRANCE: + return "TP_VIBRANCE_LABEL"; + case Tool::COLOR_APPEARANCE: + return "TP_COLORAPP_LABEL"; + case Tool::WHITE_BALANCE: + return "TP_WBALANCE_LABEL"; + case Tool::VIGNETTING: + return "TP_VIGNETTING_LABEL"; + case Tool::RETINEX_TOOL: + return "TP_RETINEX_LABEL"; + case Tool::GRADIENT: + return "TP_GRADIENT_LABEL"; + case Tool::LOCALLAB: + return "TP_LOCALLAB_LABEL"; + case Tool::PC_VIGNETTE: + return "TP_PCVIGNETTE_LABEL"; + case Tool::PERSPECTIVE: + return "TP_PERSPECTIVE_LABEL"; + case Tool::CA_CORRECTION: + return "TP_CACORRECTION_LABEL"; + case Tool::CH_MIXER: + return "TP_CHMIXER_LABEL"; + case Tool::BLACK_WHITE: + return "TP_BWMIX_LABEL"; + case Tool::RESIZE_TOOL: + return "TP_RESIZE_LABEL"; + case Tool::PR_SHARPENING: + return "TP_PRSHARPENING_LABEL"; + case Tool::CROP_TOOL: + return "TP_CROP_LABEL"; + case Tool::ICM: + return "TP_ICM_LABEL"; + case Tool::WAVELET: + return "TP_WAVELET_LABEL"; + case Tool::DIR_PYR_EQUALIZER: + return "TP_DIRPYREQUALIZER_LABEL"; + case Tool::HSV_EQUALIZER: + return "TP_HSVEQUALIZER_LABEL"; + case Tool::FILM_SIMULATION: + return "TP_FILMSIMULATION_LABEL"; + case Tool::SOFT_LIGHT: + return "TP_SOFTLIGHT_LABEL"; + case Tool::DEHAZE: + return "TP_DEHAZE_LABEL"; + case Tool::SENSOR_BAYER: + return "TP_RAW_SENSOR_BAYER_LABEL"; + case Tool::SENSOR_XTRANS: + return "TP_RAW_SENSOR_XTRANS_LABEL"; + case Tool::BAYER_PROCESS: + return "TP_RAW_LABEL"; + case Tool::XTRANS_PROCESS: + return "TP_RAW_LABEL"; + case Tool::BAYER_PREPROCESS: + return "TP_PREPROCESS_LABEL"; + case Tool::PREPROCESS: + return "TP_PREPROCESS_LABEL"; + case Tool::DARKFRAME_TOOL: + return "TP_DARKFRAME_LABEL"; + case Tool::FLATFIELD_TOOL: + return "TP_FLATFIELD_LABEL"; + case Tool::RAW_CA_CORRECTION: + return "TP_RAWCACORR_LABEL"; + case Tool::RAW_EXPOSURE: + return "TP_EXPOS_WHITEPOINT_LABEL"; + case Tool::PREPROCESS_WB: + return "TP_PREPROCWB_LABEL"; + case Tool::BAYER_RAW_EXPOSURE: + return "TP_EXPOS_BLACKPOINT_LABEL"; + case Tool::XTRANS_RAW_EXPOSURE: + return "TP_EXPOS_BLACKPOINT_LABEL"; + case Tool::FATTAL: + return "TP_TM_FATTAL_LABEL"; + case Tool::FILM_NEGATIVE: + return "TP_FILMNEGATIVE_LABEL"; + case Tool::PD_SHARPENING: + return "TP_PDSHARPENING_LABEL"; + }; + assert(false); + return ""; +} + +/** + * A widget with buttons (packed vertically) for modifying a list store with a + * tree view. + * + * Includes buttons for moving single rows up or down and a button for removing + * selected rows. + */ +class ListEditButtons : public Gtk::Box +{ +private: + Gtk::TreeView &list; + Glib::RefPtr listStore; + Gtk::Button buttonUp; + Gtk::Button buttonDown; + Gtk::Button buttonRemove; + + sigc::signal &> signalRowsPreErase; + + void onButtonDownPressed(); + void onButtonRemovePressed(); + void onButtonUpPressed(); + void onListSelectionChanged(); + void updateButtonSensitivity(); + +public: + /** + * Constructs an edit buttons widget for modifying the provided list store. + * + * @param list The tree view for which selections are made in. The tree + * view's model MUST be the list store. + * @param listStore The list store that the widget will modify. + */ + explicit ListEditButtons(Gtk::TreeView &list, Glib::RefPtr listStore); + + /** + * Returns the signal that gets emitted right before this widget removes + * rows from its list store. + * + * The signal contains a vector of tree model paths of the rows that will be + * erased. + */ + sigc::signal &> getSignalRowsPreErase() const; +}; + +/** + * Model columns for the favorites list. + */ +class FavoritesColumns : public Gtk::TreeModelColumnRecord +{ +public: + /** The tool's display name. */ + Gtk::TreeModelColumn toolName; + /** The tool. */ + Gtk::TreeModelColumn tool; + + FavoritesColumns() + { + add(toolName); + add(tool); + } +}; + +/** + * Model columns for the available tools list. + */ +class ToolListColumns : public Gtk::TreeModelColumnRecord +{ +public: + /** The tool's display name. */ + Gtk::TreeModelColumn toolName; + /** The tool. */ + Gtk::TreeModelColumn tool; + /** Is the tool added to favorites. */ + Gtk::TreeModelColumn isFavorite; + /** Can the tool be added to favorites. */ + Gtk::TreeModelColumn isEditable; + + ToolListColumns() + { + add(toolName); + add(tool); + add(isFavorite); + add(isEditable); + } +}; + +ListEditButtons::ListEditButtons(Gtk::TreeView &list, Glib::RefPtr listStore) : + Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL), + list(list), + listStore(listStore) +{ + assert(list.get_model() == listStore); + + // Set button images. + RTImage *image_button_up = Gtk::manage(new RTImage("arrow-up-small.png")); + RTImage *image_button_down = Gtk::manage(new RTImage("arrow-down-small.png")); + RTImage *image_button_remove = Gtk::manage(new RTImage("remove-small.png")); + buttonUp.set_image(*image_button_up); + buttonDown.set_image(*image_button_down); + buttonRemove.set_image(*image_button_remove); + + // Connect signals for changing button sensitivity. + const auto on_list_sel_changed_fun = sigc::mem_fun( + *this, &ListEditButtons::onListSelectionChanged); + const auto on_row_deleted_fun = sigc::hide(on_list_sel_changed_fun); + const auto on_row_inserted_fun = sigc::hide(on_row_deleted_fun); + list.get_selection()->signal_changed().connect(on_list_sel_changed_fun); + listStore->signal_row_deleted().connect(on_row_deleted_fun); + listStore->signal_row_inserted().connect(on_row_inserted_fun); + + // Connect signals for buttons. + buttonUp.signal_pressed().connect(sigc::mem_fun( + *this, &ListEditButtons::onButtonUpPressed)); + buttonDown.signal_pressed().connect(sigc::mem_fun( + *this, &ListEditButtons::onButtonDownPressed)); + buttonRemove.signal_pressed().connect(sigc::mem_fun( + *this, &ListEditButtons::onButtonRemovePressed)); + + updateButtonSensitivity(); + + add(buttonUp); + add(buttonDown); + add(buttonRemove); +} + +void ListEditButtons::onButtonDownPressed() +{ + const auto list_children = listStore->children(); + const std::vector selected = + list.get_selection()->get_selected_rows(); + + if (selected.size() != 1) { // Only one can be selected. + return; + } + + // Get the selected row and next row. + const auto selected_row_iter = listStore->get_iter(selected[0]); + auto next_row_iter = selected_row_iter; + next_row_iter++; + + if (next_row_iter == list_children.end()) { // Can't be last row. + return; + } + + // Move the selected row down and update the buttons. + listStore->iter_swap(selected_row_iter, next_row_iter); + updateButtonSensitivity(); +} + +void ListEditButtons::onButtonRemovePressed() +{ + const std::vector selected_paths = + list.get_selection()->get_selected_rows(); + std::vector selected(selected_paths.size()); + + // Get row references, which are valid until the row is removed. + std::transform( + selected_paths.begin(), + selected_paths.end(), + selected.begin(), + [this](const Gtk::TreeModel::Path &row_path) { + return Gtk::TreeModel::RowReference(listStore, row_path); + }); + + signalRowsPreErase.emit(selected_paths); + + // Remove the selected rows. + for (const auto &row_ref : selected) { + const auto row_path = row_ref.get_path(); + if (row_path) { + listStore->erase(listStore->get_iter(row_path)); + } else if (rtengine::settings->verbose) { + std::cout << "Unable to remove row because it does not exist anymore." << std::endl; + } + } + + updateButtonSensitivity(); +} + +void ListEditButtons::onButtonUpPressed() +{ + const auto list_children = listStore->children(); + const std::vector selected = + list.get_selection()->get_selected_rows(); + + if (selected.size() != 1) { // Only one can be selected. + return; + } + + const auto selected_row_iter = listStore->get_iter(selected[0]); + + if (selected_row_iter == list_children.begin()) { // Can't be first row. + return; + } + + // Swap selected row with the previous row. + auto prev_row_iter = selected_row_iter; + prev_row_iter--; + listStore->iter_swap(selected_row_iter, prev_row_iter); + updateButtonSensitivity(); +} + +void ListEditButtons::onListSelectionChanged() +{ + updateButtonSensitivity(); +} + +void ListEditButtons::updateButtonSensitivity() +{ + assert(list.get_model() == listStore); + + const std::vector selected = + list.get_selection()->get_selected_rows(); + + // Update sensitivity of the move up/down buttons. + if (selected.size() != 1) { + // Items can only be moved if one row is selected. + buttonDown.set_sensitive(false); + buttonUp.set_sensitive(false); + } else { + // Up button cannot be used on the first row. Down button cannot be used + // on the last row. + auto selected_row_iter = list.get_model()->get_iter(selected[0]); + const auto list_children = listStore->children(); + buttonUp.set_sensitive(!selected_row_iter->equal(list_children.begin())); + buttonDown.set_sensitive(!(++selected_row_iter)->equal(list_children.end())); + } + + // Update sensitivity of the remove button. + buttonRemove.set_sensitive(selected.size() > 0); +} + +sigc::signal &> +ListEditButtons::getSignalRowsPreErase() const +{ + return signalRowsPreErase; +} + +} + +struct ToolLocationPreference::Impl { + Options &options; + + // General options. + Gtk::CheckButton *cloneFavoriteToolsToggleWidget; + + // Tool list. + ToolListColumns toolListColumns; + Glib::RefPtr toolListModelPtr; + Gtk::CellRendererToggle toolListCellRendererFavorite; + Gtk::CellRendererText toolListCellRendererToolName; + Gtk::TreeViewColumn toolListViewColumnFavorite; + Gtk::TreeViewColumn toolListViewColumnToolName; + Gtk::TreeView *toolListViewPtr; + std::unordered_map + toolListToolToRowIterMap; + + // Favorites list. + FavoritesColumns favoritesColumns; + Glib::RefPtr favoritesModelPtr; + Gtk::CellRendererText favoritesCellRendererToolName; + Gtk::TreeViewColumn favoritesViewColumnToolName; + Gtk::TreeView *favoritesViewPtr; + ListEditButtons favoritesListEditButtons; + + /** + * Constructs an implementation that gets values from and updates the + * provided options object. + */ + explicit Impl(Options &options); + + /** + * Adds the tools in the tool tree as a child in the provided row. + * + * @param tools The tool tree. + * @param parentRowIter An iterator to the row under which to add the tools. + * @param favorites The tools which are currently marked as favorites. + */ + void addToolListRowGroup( + const std::vector &tools, + const Gtk::TreeIter &parentRowIter, + const Favorites &favorites); + /** + * Toggles the tool list favorite column and updates the favorites list. + * + * @param row_path Path to the tool list model row. + */ + void favoriteToggled(const Glib::ustring &row_path); + /** + * Initializes the favorites list. + * + * @param favorites Tools that are currently marked as favorites. + */ + void initFavoritesRows(const std::vector &favorites); + /** + * Initializes the available tools list. + * + * @param favorites Tools that are currently marked as favorites. + */ + void initToolListRows(const std::vector &favorites); + /** + * Updates the favorites column of the available tools list when tools are + * about to be removed from the favorites list. + * + * @param paths Paths in the favorites list pointing to the rows that are + * about to be removed. + */ + void onFavoritesRowsPreRemove(const std::vector &paths); + /** + * Converts tool names to their corresponding tools. + * + * @param tool_names The tool names that need to be converted. + * @return The tools. + */ + std::vector toolNamesToTools( + const std::vector &tool_names) const; + /** + * Updates the options object associated with this object with the current + * favorites preferences. + */ + void updateOptions(); +}; + +ToolLocationPreference::Impl::Impl(Options &options) : + options(options), + + // General options. + cloneFavoriteToolsToggleWidget(Gtk::manage( + new Gtk::CheckButton(M("PREFERENCES_TOOLPANEL_CLONE_FAVORITES")))), + + // Tool list. + toolListModelPtr(Gtk::TreeStore::create(toolListColumns)), + toolListViewColumnFavorite( + Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_FAVORITE"))), + toolListViewColumnToolName( + Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_TOOL"))), + toolListViewPtr(Gtk::manage(new Gtk::TreeView(toolListModelPtr))), + + // Favorites list. + favoritesModelPtr(Gtk::ListStore::create(favoritesColumns)), + favoritesViewColumnToolName( + Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_TOOL"))), + favoritesViewPtr(Gtk::manage(new Gtk::TreeView(favoritesModelPtr))), + favoritesListEditButtons(*favoritesViewPtr, favoritesModelPtr) +{ + const std::vector favorites = toolNamesToTools(options.favorites); + + // General options. + cloneFavoriteToolsToggleWidget->set_active(options.cloneFavoriteTools); + cloneFavoriteToolsToggleWidget->set_tooltip_text( + M("PREFERENCES_TOOLPANEL_CLONE_FAVORITES_TOOLTIP")); + + // Tool list. + toolListViewPtr->append_column(toolListViewColumnToolName); + toolListViewColumnToolName.pack_start(toolListCellRendererToolName); + toolListViewColumnToolName.set_expand(); + toolListViewColumnToolName.set_renderer( + toolListCellRendererToolName, toolListColumns.toolName); + toolListViewPtr->append_column(toolListViewColumnFavorite); + toolListViewColumnFavorite.pack_start(toolListCellRendererFavorite); + toolListViewColumnFavorite.set_expand(false); + toolListViewColumnFavorite.set_renderer( + toolListCellRendererFavorite, toolListColumns.isFavorite); + toolListViewColumnFavorite.add_attribute( + toolListCellRendererFavorite.property_visible(), toolListColumns.isEditable); + toolListCellRendererFavorite.signal_toggled().connect( + sigc::mem_fun(*this, &ToolLocationPreference::Impl::favoriteToggled)); + initToolListRows(favorites); + toolListViewPtr->expand_all(); + + // Favorites list. + favoritesViewPtr->append_column(favoritesViewColumnToolName); + favoritesViewPtr->set_reorderable(true); + favoritesViewColumnToolName.pack_start(favoritesCellRendererToolName); + favoritesViewColumnToolName.set_renderer( + favoritesCellRendererToolName, favoritesColumns.toolName); + favoritesListEditButtons.getSignalRowsPreErase().connect(sigc::mem_fun( + *this, &ToolLocationPreference::Impl::onFavoritesRowsPreRemove)); + favoritesViewPtr->get_selection()->set_mode( + Gtk::SelectionMode::SELECTION_MULTIPLE); + initFavoritesRows(favorites); +} + +void ToolLocationPreference::Impl::favoriteToggled(const Glib::ustring &row_path) +{ + auto row_iter = toolListModelPtr->get_iter(row_path); + const bool is_favorite = !row_iter->get_value(toolListColumns.isFavorite); + const Tool tool = row_iter->get_value(toolListColumns.tool); + + // Update favorite column in the tool list. + row_iter->set_value(toolListColumns.isFavorite, is_favorite); + + // Update the favorites list. + if (is_favorite) { + // Add to favorites list. + const auto new_favorite_row_iter = favoritesModelPtr->append(); + new_favorite_row_iter->set_value( + favoritesColumns.toolName, + M(getToolTitleKey(tool))); + new_favorite_row_iter->set_value(favoritesColumns.tool, tool); + } else { + // Remove from favorites list. + const auto favorites_rows = favoritesModelPtr->children(); + auto row = favorites_rows.begin(); + while ( + row != favorites_rows.end() && + row->get_value(favoritesColumns.tool) != tool) { + row++; + } + if (row != favorites_rows.end()) { + favoritesModelPtr->erase(row); + } + } +} + +void ToolLocationPreference::Impl::initFavoritesRows( + const std::vector &favorites) +{ + // Add the favorites to the favorites list store. + for (const auto tool : favorites) { + const auto favorite_row_iter = favoritesModelPtr->append(); + favorite_row_iter->set_value( + favoritesColumns.toolName, + M(getToolTitleKey(tool))); + favorite_row_iter->set_value(favoritesColumns.tool, tool); + } +} + +void ToolLocationPreference::Impl::addToolListRowGroup( + const std::vector &tools, + const Gtk::TreeIter &parentRowIter, + const Favorites &favorites) +{ + // Recursively add the tool and its children to the tool list tree store. + for (const ToolPanelCoordinator::ToolTree &tool : tools) { + const auto tool_row_iter = + toolListModelPtr->append(parentRowIter->children()); + tool_row_iter->set_value( + toolListColumns.toolName, + M(getToolTitleKey(tool.id))); + tool_row_iter->set_value(toolListColumns.tool, tool.id); + tool_row_iter->set_value( + toolListColumns.isFavorite, + favorites.count(tool.id) > 0); + tool_row_iter->set_value( + toolListColumns.isEditable, + ToolPanelCoordinator::isFavoritable(tool.id)); + toolListToolToRowIterMap[tool.id] = tool_row_iter; + addToolListRowGroup(tool.children, tool_row_iter, favorites); + } +}; + +void ToolLocationPreference::Impl::initToolListRows(const std::vector &favorites) +{ + const auto panel_tools = ToolPanelCoordinator::getDefaultToolLayout(); + Favorites favorites_set; + + // Convert the favorites vector into a set for fast lookup. + for (const auto &tool : favorites) { + favorites_set.insert(tool); + } + + // Add each panel and their children to the tool list. + for (const auto panel : { + ToolPanelCoordinator::Panel::EXPOSURE, + ToolPanelCoordinator::Panel::DETAILS, + ToolPanelCoordinator::Panel::COLOR, + ToolPanelCoordinator::Panel::ADVANCED, + ToolPanelCoordinator::Panel::LOCALLAB, + ToolPanelCoordinator::Panel::TRANSFORM_PANEL, + ToolPanelCoordinator::Panel::RAW, + }) { + const auto tool_group_iter = toolListModelPtr->append(); + tool_group_iter->set_value( + toolListColumns.toolName, + M(getToolPanelTitleKey(panel))); + addToolListRowGroup(panel_tools.at(panel), tool_group_iter, favorites_set); + } +} + +void ToolLocationPreference::Impl::onFavoritesRowsPreRemove( + const std::vector &paths) +{ + // Unset the favorite column in the tools list for tools about to be removed + // from the favorites list. + for (const auto &path : paths) { + const auto &row_iter = toolListToolToRowIterMap.at( + favoritesModelPtr->get_iter(path)->get_value(favoritesColumns.tool)); + row_iter->set_value(toolListColumns.isFavorite, false); + } +} + +std::vector ToolLocationPreference::Impl::toolNamesToTools( + const std::vector &tool_names) const +{ + std::vector tool_set; + + for (const auto &tool_name : tool_names) { + Tool tool; + try { + tool = ToolPanelCoordinator::getToolFromName(tool_name); + } catch (const std::out_of_range &e) { + if (rtengine::settings->verbose) { + std::cerr + << "Unrecognized tool name \"" << tool_name << "\"." + << std::endl; + } + assert(false); + continue; + } + tool_set.push_back(tool); + } + + return tool_set; +} + +void ToolLocationPreference::Impl::updateOptions() +{ + options.cloneFavoriteTools = cloneFavoriteToolsToggleWidget->get_active(); + + const auto favorites_rows = favoritesModelPtr->children(); + options.favorites.resize(favorites_rows.size()); + for (Gtk::TreeNodeChildren::size_type i = 0; i < favorites_rows.size(); i++) { + const Tool tool = favorites_rows[i].get_value(favoritesColumns.tool); + options.favorites[i] = ToolPanelCoordinator::getToolName(tool); + } +} + +ToolLocationPreference::ToolLocationPreference(Options &options) : + impl(new Impl(options)) +{ + // Layout grid. + Gtk::Grid *layout_grid = Gtk::manage(new Gtk::Grid()); + layout_grid->set_column_spacing(4); + layout_grid->set_row_spacing(4); + add(*layout_grid); + + // Tool list. + Gtk::Frame *tool_list_frame = Gtk::manage(new Gtk::Frame( + M("PREFERENCES_TOOLPANEL_AVAILABLETOOLS"))); + Gtk::ScrolledWindow *tool_list_scrolled_window = + Gtk::manage(new Gtk::ScrolledWindow()); + tool_list_scrolled_window->set_min_content_width( + 400 * (RTScalable::getTweakedDPI() / RTScalable::baseDPI)); + layout_grid->attach_next_to(*tool_list_frame, Gtk::PositionType::POS_RIGHT, 1, 1); + tool_list_frame->add(*tool_list_scrolled_window); + tool_list_scrolled_window->add(*impl->toolListViewPtr); + setExpandAlignProperties( + tool_list_frame, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); + + // Favorites list. + Gtk::Frame *favorites_frame = Gtk::manage(new Gtk::Frame( + M("PREFERENCES_TOOLPANEL_FAVORITESPANEL"))); + Gtk::Box *favorites_box = Gtk::manage(new Gtk::Box()); + Gtk::ScrolledWindow *favorites_list_scrolled_window = + Gtk::manage(new Gtk::ScrolledWindow()); + favorites_list_scrolled_window->set_min_content_width( + 300 * (RTScalable::getTweakedDPI() / RTScalable::baseDPI)); + layout_grid->attach_next_to(*favorites_frame, Gtk::PositionType::POS_RIGHT, 1, 1); + favorites_box->pack_start(impl->favoritesListEditButtons, false, false); + favorites_box->pack_start(*favorites_list_scrolled_window, false, false); + favorites_frame->add(*favorites_box); + favorites_list_scrolled_window->add(*impl->favoritesViewPtr); + setExpandAlignProperties( + favorites_frame, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); + + // General options. + layout_grid->attach_next_to( + *impl->cloneFavoriteToolsToggleWidget, Gtk::PositionType::POS_BOTTOM, 2, 1); +} + +void ToolLocationPreference::updateOptions() +{ + impl->updateOptions(); +} diff --git a/rtgui/toollocationpref.h b/rtgui/toollocationpref.h new file mode 100644 index 000000000..c7bee8695 --- /dev/null +++ b/rtgui/toollocationpref.h @@ -0,0 +1,45 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 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 + +class Options; + +/** + * Widget for configuring the location of tools in the tool panel tabs. + */ +class ToolLocationPreference : public Gtk::Box +{ +private: + struct Impl; + std::unique_ptr impl; + +public: + /** + * Constructs a tool location preference widget that gets values from and + * updates the provided options object. + */ + explicit ToolLocationPreference(Options &options); + /** + * Updates the options object associated with this object with the current + * favorites preferences. + */ + void updateOptions(); +}; diff --git a/rtgui/toolpanel.cc b/rtgui/toolpanel.cc index 2024e76cc..c49da6caa 100644 --- a/rtgui/toolpanel.cc +++ b/rtgui/toolpanel.cc @@ -38,6 +38,7 @@ ToolVBox::ToolVBox() { ToolParamBlock::ToolParamBlock() { set_orientation(Gtk::ORIENTATION_VERTICAL); + get_style_context()->add_class("ToolParamBlock"); //GTK318 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20 set_spacing(2); // Vertical space between parameters in a single tool @@ -73,7 +74,15 @@ FoldableToolPanel::FoldableToolPanel(Gtk::Box* content, Glib::ustring toolName, exp->signal_button_release_event().connect_notify( sigc::mem_fun(this, &FoldableToolPanel::foldThemAll) ); enaConn = signal_enabled_toggled().connect( sigc::mem_fun(*this, &FoldableToolPanel::enabled_toggled) ); - exp->add (*content); + Gtk::Box *expanderContents = Gtk::manage( + new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + subToolsContainer = Gtk::manage(new ToolParamBlock()); + subToolsContainer->get_style_context()->add_class("SubToolsContainer"); + expanderContents->get_style_context()->add_class("ExpanderContents"); + expanderContents->pack_start(*content, false, false, 0); + expanderContents->pack_start(*subToolsContainer, false, false, 0); + + exp->add(*expanderContents, false); exp->show (); } diff --git a/rtgui/toolpanel.h b/rtgui/toolpanel.h index 8fdb4540d..5ec59c9c2 100644 --- a/rtgui/toolpanel.h +++ b/rtgui/toolpanel.h @@ -98,6 +98,10 @@ public: { return nullptr; } + virtual ToolParamBlock *getSubToolsContainer() const + { + return nullptr; + } virtual void setExpanded (bool expanded) {} virtual bool getExpanded () { @@ -164,6 +168,7 @@ class FoldableToolPanel : protected: Gtk::Box* parentContainer; MyExpander* exp; + ToolParamBlock *subToolsContainer; bool lastEnabled; sigc::connection enaConn; void foldThemAll (GdkEventButton* event); @@ -177,6 +182,12 @@ public: { return exp; } + + ToolParamBlock *getSubToolsContainer() const final + { + return subToolsContainer; + } + void setExpanded (bool expanded) final { if (exp) { diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 731b70e68..a2a17e905 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include + #include "multilangmgr.h" #include "toolpanelcoord.h" #include "metadatapanel.h" @@ -32,7 +34,244 @@ using namespace rtengine::procparams; -ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favoritePanelSW(nullptr), hasChanged (false), editDataProvider (nullptr), photoLoadedOnce(false), ornamentSurface(new RTSurface("ornament1.svg")) +using Tool = ToolPanelCoordinator::Tool; +using ToolTree = ToolPanelCoordinator::ToolTree; + +const std::vector EXPOSURE_PANEL_TOOLS = { + { + .id = Tool::TONE_CURVE, + }, + { + .id = Tool::SHADOWS_HIGHLIGHTS, + }, + { + .id = Tool::EPD, + }, + { + .id = Tool::FATTAL, + }, + { + .id = Tool::PC_VIGNETTE, + }, + { + .id = Tool::GRADIENT, + }, + { + .id = Tool::L_CURVE, + }, +}; + +const std::vector DETAILS_PANEL_TOOLS = { + { + .id = Tool::SPOT, + }, + { + .id = Tool::SHARPENING_TOOL, + }, + { + .id = Tool::LOCAL_CONTRAST, + }, + { + .id = Tool::SHARPEN_EDGE, + }, + { + .id = Tool::SHARPEN_MICRO, + }, + { + .id = Tool::IMPULSE_DENOISE, + }, + { + .id = Tool::DIR_PYR_DENOISE, + }, + { + .id = Tool::DEFRINGE_TOOL, + }, + { + .id = Tool::DIR_PYR_EQUALIZER, + }, + { + .id = Tool::DEHAZE, + }, +}; + +const std::vector COLOR_PANEL_TOOLS = { + { + .id = Tool::WHITE_BALANCE, + }, + { + .id = Tool::VIBRANCE, + }, + { + .id = Tool::CH_MIXER, + }, + { + .id = Tool::BLACK_WHITE, + }, + { + .id = Tool::HSV_EQUALIZER, + }, + { + .id = Tool::FILM_SIMULATION, + }, + { + .id = Tool::FILM_NEGATIVE, + }, + { + .id = Tool::SOFT_LIGHT, + }, + { + .id = Tool::RGB_CURVES, + }, + { + .id = Tool::COLOR_TONING, + }, + { + .id = Tool::ICM, + }, +}; + +const std::vector ADVANCED_PANEL_TOOLS = { + { + .id = Tool::RETINEX_TOOL, + }, + { + .id = Tool::COLOR_APPEARANCE, + }, + { + .id = Tool::WAVELET, + }, +}; + +const std::vector LOCALLAB_PANEL_TOOLS = { + { + .id = Tool::LOCALLAB, + }, +}; + +const std::vector TRANSFORM_PANEL_TOOLS = { + { + .id = Tool::CROP_TOOL, + }, + { + .id = Tool::RESIZE_TOOL, + .children = { + { + .id = Tool::PR_SHARPENING, + }, + }, + }, + { + .id = Tool::LENS_GEOM, + .children = { + { + .id = Tool::ROTATE, + }, + { + .id = Tool::PERSPECTIVE, + }, + { + .id = Tool::LENS_PROF, + }, + { + .id = Tool::DISTORTION, + }, + { + .id = Tool::CA_CORRECTION, + }, + { + .id = Tool::VIGNETTING, + }, + }, + }, +}; + +const std::vector RAW_PANEL_TOOLS = { + { + .id = Tool::SENSOR_BAYER, + .children = { + { + { + .id = Tool::BAYER_PROCESS, + }, + { + .id = Tool::BAYER_RAW_EXPOSURE, + }, + { + .id = Tool::BAYER_PREPROCESS, + }, + { + .id = Tool::RAW_CA_CORRECTION, + }, + }, + }, + }, + { + .id = Tool::SENSOR_XTRANS, + .children = { + { + { + .id = Tool::XTRANS_PROCESS, + }, + { + .id = Tool::XTRANS_RAW_EXPOSURE, + }, + }, + }, + }, + { + .id = Tool::RAW_EXPOSURE, + }, + { + .id = Tool::PREPROCESS_WB, + }, + { + .id = Tool::PREPROCESS, + }, + { + .id = Tool::DARKFRAME_TOOL, + }, + { + .id = Tool::FLATFIELD_TOOL, + }, + { + .id = Tool::PD_SHARPENING, + }, +}; + +const ToolPanelCoordinator::ToolLayout PANEL_TOOLS = { + { + ToolPanelCoordinator::Panel::EXPOSURE, + EXPOSURE_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::DETAILS, + DETAILS_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::COLOR, + COLOR_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::ADVANCED, + ADVANCED_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::LOCALLAB, + LOCALLAB_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::TRANSFORM_PANEL, + TRANSFORM_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::RAW, + RAW_PANEL_TOOLS + }, +}; + +std::unordered_map ToolPanelCoordinator::toolNamesReverseMap; + +ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favoritePanelSW(nullptr), hasChanged (false), batch(batch), editDataProvider (nullptr), photoLoadedOnce(false), ornamentSurface(new RTSurface("ornament1.svg")) { favoritePanel = Gtk::manage (new ToolVBox ()); @@ -110,71 +349,35 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit // Valeurs par dfaut: // Best -> low ISO // Medium -> High ISO - favorites.resize(options.favorites.size(), nullptr); - addfavoritePanel (colorPanel, whitebalance); - addfavoritePanel (exposurePanel, toneCurve); - addfavoritePanel (colorPanel, vibrance); - addfavoritePanel (colorPanel, chmixer); - addfavoritePanel (colorPanel, blackwhite); - addfavoritePanel (exposurePanel, shadowshighlights); - addfavoritePanel (detailsPanel, spot); - addfavoritePanel (detailsPanel, sharpening); - addfavoritePanel (detailsPanel, localContrast); - addfavoritePanel (detailsPanel, sharpenEdge); - addfavoritePanel (detailsPanel, sharpenMicro); - addfavoritePanel (colorPanel, hsvequalizer); - addfavoritePanel (colorPanel, filmSimulation); - addfavoritePanel (colorPanel, filmNegative); - addfavoritePanel (colorPanel, softlight); - addfavoritePanel (colorPanel, rgbcurves); - addfavoritePanel (colorPanel, colortoning); - addfavoritePanel (exposurePanel, epd); - addfavoritePanel (exposurePanel, fattal); - addfavoritePanel (advancedPanel, retinex); - addfavoritePanel (exposurePanel, pcvignette); - addfavoritePanel (exposurePanel, gradient); - addfavoritePanel (exposurePanel, lcurve); - addfavoritePanel (advancedPanel, colorappearance); - addfavoritePanel (detailsPanel, impulsedenoise); - addfavoritePanel (detailsPanel, dirpyrdenoise); - addfavoritePanel (detailsPanel, defringe); - addfavoritePanel (detailsPanel, dirpyrequalizer); - addfavoritePanel (detailsPanel, dehaze); - addfavoritePanel (advancedPanel, wavelet); - addfavoritePanel(locallabPanel, locallab); + for (const auto &panel_tool_layout : getDefaultToolLayout()) { + const auto &panel_tools = panel_tool_layout.second; + std::vector unprocessed_tools(panel_tools.size()); - addfavoritePanel (transformPanel, crop); - addfavoritePanel (transformPanel, resize); - addPanel (resize->getPackBox(), prsharpening, 2); - addfavoritePanel (transformPanel, lensgeom); - addfavoritePanel (lensgeom->getPackBox(), rotate, 2); - addfavoritePanel (lensgeom->getPackBox(), perspective, 2); - addfavoritePanel (lensgeom->getPackBox(), lensProf, 2); - addfavoritePanel (lensgeom->getPackBox(), distortion, 2); - addfavoritePanel (lensgeom->getPackBox(), cacorrection, 2); - addfavoritePanel (lensgeom->getPackBox(), vignetting, 2); - addfavoritePanel (colorPanel, icm); - addfavoritePanel (rawPanel, sensorbayer); - addfavoritePanel (sensorbayer->getPackBox(), bayerprocess, 2); - addfavoritePanel (sensorbayer->getPackBox(), bayerrawexposure, 2); - addfavoritePanel (sensorbayer->getPackBox(), bayerpreprocess, 2); - addfavoritePanel (sensorbayer->getPackBox(), rawcacorrection, 2); - addfavoritePanel (rawPanel, sensorxtrans); - addfavoritePanel (sensorxtrans->getPackBox(), xtransprocess, 2); - addfavoritePanel (sensorxtrans->getPackBox(), xtransrawexposure, 2); - addfavoritePanel (rawPanel, rawexposure); - addfavoritePanel (rawPanel, preprocessWB); - addfavoritePanel (rawPanel, preprocess); - addfavoritePanel (rawPanel, darkframe); - addfavoritePanel (rawPanel, flatfield); - addfavoritePanel (rawPanel, pdSharpening); + // Start with the root tools for every panel. + std::transform( + panel_tools.begin(), + panel_tools.end(), + unprocessed_tools.begin(), + [](const ToolTree &tool_tree) { return &tool_tree; }); - int favoriteCount = 0; - for(auto it = favorites.begin(); it != favorites.end(); ++it) { - if (*it) { - addPanel(favoritePanel, *it); - ++favoriteCount; + // Process each tool. + while (!unprocessed_tools.empty()) { + // Pop from stack of unprocessed. + const ToolTree *cur_tool = unprocessed_tools.back(); + unprocessed_tools.pop_back(); + // Add tool to list of expanders and tool panels. + FoldableToolPanel *const tool_panel = getFoldableToolPanel(*cur_tool); + expList.push_back(tool_panel->getExpander()); + toolPanels.push_back(tool_panel); + expanderToToolPanelMap[tool_panel->getExpander()] = tool_panel; + toolToDefaultToolTreeMap[cur_tool->id] = cur_tool; + // Show all now, since they won't be attached to a parent. + tool_panel->getExpander()->show_all(); + // Add children to unprocessed. + for (const auto &child_tool : cur_tool->children) { + unprocessed_tools.push_back(&child_tool); + } } } @@ -183,6 +386,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toolPanelNotebook = new Gtk::Notebook(); toolPanelNotebook->set_name("ToolPanelNotebook"); + favoritePanelSW.reset(new MyScrolledWindow()); exposurePanelSW = Gtk::manage (new MyScrolledWindow ()); detailsPanelSW = Gtk::manage (new MyScrolledWindow ()); colorPanelSW = Gtk::manage (new MyScrolledWindow ()); @@ -196,38 +400,63 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit vbPanelEnd[i] = Gtk::manage (new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); imgPanelEnd[i] = Gtk::manage (new Gtk::Image (ornamentSurface->get())); imgPanelEnd[i]->show(); + vbPanelEnd[i]->get_style_context()->add_class("PanelEnding"); vbPanelEnd[i]->pack_start(*imgPanelEnd[i], Gtk::PACK_SHRINK); vbPanelEnd[i]->show_all(); } - if(favoriteCount > 0) { - favoritePanelSW = Gtk::manage(new MyScrolledWindow()); - favoritePanelSW->add(*favoritePanel); - favoritePanel->pack_start(*vbPanelEnd[0], Gtk::PACK_SHRINK, 4); - } updateVScrollbars(options.hideTPVScrollbar); - exposurePanelSW->add (*exposurePanel); - exposurePanel->pack_start (*vbPanelEnd[1], Gtk::PACK_SHRINK, 4); + Gtk::Box *favoritePanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *exposurePanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *detailsPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *colorPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *advancedPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *locallabPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *transformPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *rawPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); - detailsPanelSW->add (*detailsPanel); - detailsPanel->pack_start (*vbPanelEnd[2], Gtk::PACK_SHRINK, 4); + favoritePanelSW->add(*favoritePanelContainer); + favoritePanelContainer->pack_start(*favoritePanel, Gtk::PACK_SHRINK); + favoritePanelContainer->pack_start(*vbPanelEnd[0], Gtk::PACK_SHRINK); + favoritePanelSW->show_all(); - colorPanelSW->add (*colorPanel); - colorPanel->pack_start (*vbPanelEnd[3], Gtk::PACK_SHRINK, 4); + exposurePanelSW->add (*exposurePanelContainer); + exposurePanelContainer->pack_start(*exposurePanel, Gtk::PACK_SHRINK); + exposurePanelContainer->pack_start (*vbPanelEnd[1], Gtk::PACK_SHRINK); - advancedPanelSW->add (*advancedPanel); - advancedPanel->pack_start (*vbPanelEnd[6], Gtk::PACK_SHRINK, 0); + detailsPanelSW->add (*detailsPanelContainer); + detailsPanelContainer->pack_start(*detailsPanel, Gtk::PACK_SHRINK); + detailsPanelContainer->pack_start (*vbPanelEnd[2], Gtk::PACK_SHRINK); - locallabPanelSW->add(*locallabPanel); - locallabPanel->pack_start(*vbPanelEnd[7], Gtk::PACK_SHRINK, 4); + colorPanelSW->add (*colorPanelContainer); + colorPanelContainer->pack_start(*colorPanel, Gtk::PACK_SHRINK); + colorPanelContainer->pack_start (*vbPanelEnd[3], Gtk::PACK_SHRINK); - transformPanelSW->add (*transformPanel); - transformPanel->pack_start (*vbPanelEnd[4], Gtk::PACK_SHRINK, 4); + advancedPanelSW->add (*advancedPanelContainer); + advancedPanelContainer->pack_start(*advancedPanel, Gtk::PACK_SHRINK); + advancedPanelContainer->pack_start (*vbPanelEnd[6], Gtk::PACK_SHRINK); - rawPanelSW->add (*rawPanel); - rawPanel->pack_start (*vbPanelEnd[5], Gtk::PACK_SHRINK, 0); + locallabPanelSW->add(*locallabPanelContainer); + locallabPanelContainer->pack_start(*locallabPanel, Gtk::PACK_SHRINK); + locallabPanelContainer->pack_start(*vbPanelEnd[7], Gtk::PACK_SHRINK); - toiF = Gtk::manage (new TextOrIcon ("star", M ("MAIN_TAB_FAVORITES"), M ("MAIN_TAB_FAVORITES_TOOLTIP"))); + transformPanelSW->add (*transformPanelContainer); + transformPanelContainer->pack_start(*transformPanel, Gtk::PACK_SHRINK); + transformPanelContainer->pack_start (*vbPanelEnd[4], Gtk::PACK_SHRINK); + + rawPanelSW->add (*rawPanelContainer); + rawPanelContainer->pack_start(*rawPanel, Gtk::PACK_SHRINK); + rawPanelContainer->pack_start (*vbPanelEnd[5], Gtk::PACK_SHRINK); + + toiF.reset(new TextOrIcon ("star", M ("MAIN_TAB_FAVORITES"), M ("MAIN_TAB_FAVORITES_TOOLTIP"))); toiE = Gtk::manage (new TextOrIcon ("exposure", M ("MAIN_TAB_EXPOSURE"), M ("MAIN_TAB_EXPOSURE_TOOLTIP"))); toiD = Gtk::manage (new TextOrIcon ("detail", M ("MAIN_TAB_DETAIL"), M ("MAIN_TAB_DETAIL_TOOLTIP"))); toiC = Gtk::manage (new TextOrIcon ("color-circles", M ("MAIN_TAB_COLOR"), M ("MAIN_TAB_COLOR_TOOLTIP"))); @@ -237,8 +466,9 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toiT = Gtk::manage (new TextOrIcon ("transform", M ("MAIN_TAB_TRANSFORM"), M ("MAIN_TAB_TRANSFORM_TOOLTIP"))); toiR = Gtk::manage (new TextOrIcon ("bayer", M ("MAIN_TAB_RAW"), M ("MAIN_TAB_RAW_TOOLTIP"))); toiM = Gtk::manage (new TextOrIcon ("metadata", M ("MAIN_TAB_METADATA"), M ("MAIN_TAB_METADATA_TOOLTIP"))); - if (favoritePanelSW) { - toolPanelNotebook->append_page (*favoritePanelSW, *toiF); + toiF->show_all(); + if (options.favorites.size()) { + toolPanelNotebook->append_page(*favoritePanelSW, *toiF); } toolPanelNotebook->append_page (*exposurePanelSW, *toiE); toolPanelNotebook->append_page (*detailsPanelSW, *toiD); @@ -256,6 +486,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toolPanelNotebook->set_scrollable(); toolPanelNotebook->show_all(); + updateToolLocations(options.favorites, options.cloneFavoriteTools); notebookconn = toolPanelNotebook->signal_switch_page().connect( sigc::mem_fun(*this, &ToolPanelCoordinator::notebookPageChanged)); @@ -288,8 +519,175 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit prevPage = toolPanelNotebook->get_nth_page(0); } +const ToolPanelCoordinator::ToolLayout &ToolPanelCoordinator::getDefaultToolLayout() +{ + return PANEL_TOOLS; +} + +Tool ToolPanelCoordinator::getToolFromName(const std::string &name) +{ + if (toolNamesReverseMap.empty()) { + // Create the name to tool mapping. + + const auto panels = ToolPanelCoordinator::getDefaultToolLayout(); + std::vector unprocessed_tool_trees; + + // Get the root tools from each panel. + for (const auto &panel_tools : panels) { + for (const auto &tool : panel_tools.second) { + unprocessed_tool_trees.push_back(&tool); + } + } + + // Process all the tools, including their children. + while (unprocessed_tool_trees.size() > 0) { + const ToolPanelCoordinator::ToolTree *tool_tree = + unprocessed_tool_trees.back(); + unprocessed_tool_trees.pop_back(); + toolNamesReverseMap[getToolName(tool_tree->id)] = tool_tree->id; + for (const auto &child_tree : tool_tree->children) { + unprocessed_tool_trees.push_back(&child_tree); + } + } + } + + return toolNamesReverseMap.at(name); +} + +std::string ToolPanelCoordinator::getToolName(Tool tool) +{ + switch (tool) { + case Tool::TONE_CURVE: + return ToneCurve::TOOL_NAME; + case Tool::SHADOWS_HIGHLIGHTS: + return ShadowsHighlights::TOOL_NAME; + case Tool::IMPULSE_DENOISE: + return ImpulseDenoise::TOOL_NAME; + case Tool::DEFRINGE_TOOL: + return Defringe::TOOL_NAME; + case Tool::SPOT: + return Spot::TOOL_NAME; + case Tool::DIR_PYR_DENOISE: + return DirPyrDenoise::TOOL_NAME; + case Tool::EPD: + return EdgePreservingDecompositionUI::TOOL_NAME; + case Tool::SHARPENING_TOOL: + return Sharpening::TOOL_NAME; + case Tool::LOCAL_CONTRAST: + return LocalContrast::TOOL_NAME; + case Tool::SHARPEN_EDGE: + return SharpenEdge::TOOL_NAME; + case Tool::SHARPEN_MICRO: + return SharpenMicro::TOOL_NAME; + case Tool::L_CURVE: + return LCurve::TOOL_NAME; + case Tool::RGB_CURVES: + return RGBCurves::TOOL_NAME; + case Tool::COLOR_TONING: + return ColorToning::TOOL_NAME; + case Tool::LENS_GEOM: + return LensGeometry::TOOL_NAME; + case Tool::LENS_PROF: + return LensProfilePanel::TOOL_NAME; + case Tool::DISTORTION: + return Distortion::TOOL_NAME; + case Tool::ROTATE: + return Rotate::TOOL_NAME; + case Tool::VIBRANCE: + return Vibrance::TOOL_NAME; + case Tool::COLOR_APPEARANCE: + return ColorAppearance::TOOL_NAME; + case Tool::WHITE_BALANCE: + return WhiteBalance::TOOL_NAME; + case Tool::VIGNETTING: + return Vignetting::TOOL_NAME; + case Tool::RETINEX_TOOL: + return Retinex::TOOL_NAME; + case Tool::GRADIENT: + return Gradient::TOOL_NAME; + case Tool::LOCALLAB: + return Locallab::TOOL_NAME; + case Tool::PC_VIGNETTE: + return PCVignette::TOOL_NAME; + case Tool::PERSPECTIVE: + return PerspCorrection::TOOL_NAME; + case Tool::CA_CORRECTION: + return CACorrection::TOOL_NAME; + case Tool::CH_MIXER: + return ChMixer::TOOL_NAME; + case Tool::BLACK_WHITE: + return BlackWhite::TOOL_NAME; + case Tool::RESIZE_TOOL: + return Resize::TOOL_NAME; + case Tool::PR_SHARPENING: + return PrSharpening::TOOL_NAME; + case Tool::CROP_TOOL: + return Crop::TOOL_NAME; + case Tool::ICM: + return ICMPanel::TOOL_NAME; + case Tool::WAVELET: + return Wavelet::TOOL_NAME; + case Tool::DIR_PYR_EQUALIZER: + return DirPyrEqualizer::TOOL_NAME; + case Tool::HSV_EQUALIZER: + return HSVEqualizer::TOOL_NAME; + case Tool::FILM_SIMULATION: + return FilmSimulation::TOOL_NAME; + case Tool::SOFT_LIGHT: + return SoftLight::TOOL_NAME; + case Tool::DEHAZE: + return Dehaze::TOOL_NAME; + case Tool::SENSOR_BAYER: + return SensorBayer::TOOL_NAME; + case Tool::SENSOR_XTRANS: + return SensorXTrans::TOOL_NAME; + case Tool::BAYER_PROCESS: + return BayerProcess::TOOL_NAME; + case Tool::XTRANS_PROCESS: + return XTransProcess::TOOL_NAME; + case Tool::BAYER_PREPROCESS: + return BayerPreProcess::TOOL_NAME; + case Tool::PREPROCESS: + return PreProcess::TOOL_NAME; + case Tool::DARKFRAME_TOOL: + return DarkFrame::TOOL_NAME; + case Tool::FLATFIELD_TOOL: + return FlatField::TOOL_NAME; + case Tool::RAW_CA_CORRECTION: + return RAWCACorr::TOOL_NAME; + case Tool::RAW_EXPOSURE: + return RAWExposure::TOOL_NAME; + case Tool::PREPROCESS_WB: + return PreprocessWB::TOOL_NAME; + case Tool::BAYER_RAW_EXPOSURE: + return BayerRAWExposure::TOOL_NAME; + case Tool::XTRANS_RAW_EXPOSURE: + return XTransRAWExposure::TOOL_NAME; + case Tool::FATTAL: + return FattalToneMapping::TOOL_NAME; + case Tool::FILM_NEGATIVE: + return FilmNegative::TOOL_NAME; + case Tool::PD_SHARPENING: + return PdSharpening::TOOL_NAME; + }; + assert(false); + return ""; +}; + +bool ToolPanelCoordinator::isFavoritable(Tool tool) +{ + switch (tool) { + case Tool::PR_SHARPENING: + return false; + default: + return true; + } +} + void ToolPanelCoordinator::notebookPageChanged(Gtk::Widget* page, guint page_num) { + updatePanelTools(page, options.favorites, options.cloneFavoriteTools); + // Locallab spot curves are set visible if at least one photo has been loaded (to avoid // segfault) and locallab panel is active if (photoLoadedOnce) { @@ -307,26 +705,175 @@ void ToolPanelCoordinator::notebookPageChanged(Gtk::Widget* page, guint page_num } } +void ToolPanelCoordinator::updateFavoritesPanel( + const std::vector &favoritesNames, + bool cloneFavoriteTools) +{ + std::unordered_set favorites_set; + std::vector> favorites_tool_tree; + + for (const auto &tool_name : favoritesNames) { + Tool tool; + try { + tool = getToolFromName(tool_name.raw()); + } catch (const std::out_of_range &e) { + if (rtengine::settings->verbose) { + std::cerr + << "Unrecognized favorite tool \"" << tool_name << "\"" + << std::endl; + } + continue; + } + if (isFavoritable(tool)) { + favorites_set.insert(tool); + favorites_tool_tree.push_back( + std::ref(*(toolToDefaultToolTreeMap.at(tool)))); + } + } + + updateToolPanel( + favoritePanel, favorites_tool_tree, 1, favorites_set, cloneFavoriteTools); +} + +void ToolPanelCoordinator::updatePanelTools( + Gtk::Widget *page, + const std::vector &favorites, + bool cloneFavoriteTools) +{ + if (page == favoritePanelSW.get()) { + updateFavoritesPanel(favorites, cloneFavoriteTools); + return; + } + + ToolVBox *panel = nullptr; + const std::vector *default_panel_tools = nullptr; + if (page == exposurePanelSW) { + panel = exposurePanel; + default_panel_tools = &EXPOSURE_PANEL_TOOLS; + } else if (page == detailsPanelSW) { + panel = detailsPanel; + default_panel_tools = &DETAILS_PANEL_TOOLS; + } else if (page == colorPanelSW) { + panel = colorPanel; + default_panel_tools = &COLOR_PANEL_TOOLS; + } else if (page == transformPanelSW) { + panel = transformPanel; + default_panel_tools = &TRANSFORM_PANEL_TOOLS; + } else if (page == rawPanelSW) { + panel = rawPanel; + default_panel_tools = &RAW_PANEL_TOOLS; + } else if (page == advancedPanelSW) { + panel = advancedPanel; + default_panel_tools = &ADVANCED_PANEL_TOOLS; + } else if (page == locallabPanelSW) { + panel = locallabPanel; + default_panel_tools = &LOCALLAB_PANEL_TOOLS; + } else { + return; + } + assert(panel && default_panel_tools); + + std::unordered_set favoriteTools; + for (const auto &tool_name : favorites) { + Tool tool; + try { + tool = getToolFromName(tool_name.raw()); + } catch (const std::out_of_range &e) { + if (rtengine::settings->verbose) { + std::cerr + << "Unrecognized favorite tool \"" << tool_name << "\"" + << std::endl; + } + continue; + } + if (isFavoritable(tool)) { + favoriteTools.insert(tool); + } + } + + updateToolPanel(panel, *default_panel_tools, 1, favoriteTools, cloneFavoriteTools); +} + +template +typename std::enable_if::value, void>::type +ToolPanelCoordinator::updateToolPanel( + Gtk::Box *panelBox, + const std::vector &children, + int level, + const std::unordered_set &favorites, + bool cloneFavoriteTools) +{ + const bool is_favorite_panel = panelBox == favoritePanel; + const bool skip_favorites = !cloneFavoriteTools && !is_favorite_panel; + const std::vector old_tool_panels = panelBox->get_children(); + auto old_widgets_iter = old_tool_panels.begin(); + auto new_tool_trees_iter = children.begin(); + + // Indicates if this tool should not be added. Favorite tools are skipped + // if they are sub-tools within the favorites panel, or if tool cloning is + // off and they are not within the favorites panel. + const auto should_skip_tool = + [this, skip_favorites, &favorites](const ToolTree &tool_tree) { + return (skip_favorites && favorites.count(tool_tree.id)) || + (batch && tool_tree.id == Tool::LOCALLAB); + }; + + // Keep tools that are already correct. + while ( + old_widgets_iter != old_tool_panels.end() && + new_tool_trees_iter != children.end()) { + if (should_skip_tool(*new_tool_trees_iter)) { + ++new_tool_trees_iter; + continue; + } + if (*old_widgets_iter != + getFoldableToolPanel(*new_tool_trees_iter)->getExpander()) { + break; + } + ++new_tool_trees_iter; + ++old_widgets_iter; + } + + // Remove incorrect tools. + for (auto iter = old_tool_panels.end(); iter != old_widgets_iter;) { + --iter; + FoldableToolPanel *old_tool_panel = expanderToToolPanelMap.at(*iter); + assert(*iter == old_tool_panel->getExpander()); + panelBox->remove(**iter); + old_tool_panel->setParent(nullptr); + } + + // Add correct tools. + for (; new_tool_trees_iter != children.end(); new_tool_trees_iter++) { + if (should_skip_tool(*new_tool_trees_iter)) { + continue; + } + FoldableToolPanel *tool_panel = + getFoldableToolPanel(*new_tool_trees_iter); + if (tool_panel->getParent()) { + tool_panel->getParent()->remove(*tool_panel->getExpander()); + } + addPanel(panelBox, tool_panel, level); + } + + // Update the child tools. + for (const ToolTree &tool_tree : children) { + const FoldableToolPanel *tool_panel = getFoldableToolPanel(tool_tree); + updateToolPanel( + tool_panel->getSubToolsContainer(), + tool_tree.children, + level + 1, + favorites, + cloneFavoriteTools && !is_favorite_panel); + } +} + void ToolPanelCoordinator::addPanel(Gtk::Box* where, FoldableToolPanel* panel, int level) { panel->setParent(where); panel->setLevel(level); - - 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(); - auto it = std::find(options.favorites.begin(), options.favorites.end(), name); - if (it != options.favorites.end()) { - int index = std::distance(options.favorites.begin(), it); - favorites[index] = panel; - } else { - addPanel(where, panel, level); - } } ToolPanelCoordinator::~ToolPanelCoordinator () @@ -339,16 +886,27 @@ ToolPanelCoordinator::~ToolPanelCoordinator () // which is responsible of segfault if listener isn't deactivated before notebookconn.block(true); + // Foldable tool panels manage (Gtk::manage) their expanders. Each expander + // will only be automatically deleted if attached to a parent and the parent + // is deleted. This is a hack in lieu of a potentially tedious refactoring + // of FoldableToolPanel. + std::unique_ptr hidden_tool_panel_parent(new Gtk::Box()); + for (const auto expander : expList) { + if (!expander->get_parent()) { + hidden_tool_panel_parent->add(*expander); + } + } + 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, bool isGainMapSupported) { if (isRaw) { if (isBayer) { idle_register.add( - [this]() -> bool + [this, isGainMapSupported]() -> bool { rawPanelSW->set_sensitive(true); sensorxtrans->FoldableToolPanel::hide(); @@ -362,6 +920,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr preprocessWB->FoldableToolPanel::show(); preprocess->FoldableToolPanel::show(); flatfield->FoldableToolPanel::show(); + flatfield->setGainMap(isGainMapSupported); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); return false; @@ -369,7 +928,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr ); } else if (isXtrans) { idle_register.add( - [this]() -> bool + [this, isGainMapSupported]() -> bool { rawPanelSW->set_sensitive(true); sensorxtrans->FoldableToolPanel::show(); @@ -383,6 +942,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr preprocessWB->FoldableToolPanel::show(); preprocess->FoldableToolPanel::show(); flatfield->FoldableToolPanel::show(); + flatfield->setGainMap(isGainMapSupported); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); return false; @@ -390,7 +950,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr ); } else if (isMono) { idle_register.add( - [this]() -> bool + [this, isGainMapSupported]() -> bool { rawPanelSW->set_sensitive(true); sensorbayer->FoldableToolPanel::hide(); @@ -403,6 +963,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr preprocessWB->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::show(); + flatfield->setGainMap(isGainMapSupported); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); return false; @@ -1126,6 +1687,43 @@ void ToolPanelCoordinator::foldAllButOne(Gtk::Box* parent, FoldableToolPanel* op } } +void ToolPanelCoordinator::updateToolLocations( + const std::vector &favorites, bool cloneFavoriteTools) +{ + const int fav_page_num = toolPanelNotebook->page_num(*favoritePanelSW); + + // Add or remove favorites tab if necessary. + if (favorites.empty() && fav_page_num != -1) { + toolPanelNotebook->remove_page(fav_page_num); + } else if (!favorites.empty() && fav_page_num == -1) { + toolPanelNotebook->prepend_page(*favoritePanelSW, *toiF); + } + + // Update favorite tool panels list. + favoritesToolPanels.clear(); + for (const auto &favorite_name : favorites) { + Tool tool; + try { + tool = getToolFromName(favorite_name.raw()); + } catch (const std::out_of_range &e) { + if (rtengine::settings->verbose) { + std::cerr + << "Unrecognized favorite tool \"" << favorite_name << "\"" + << std::endl; + } + continue; + } + if (isFavoritable(tool)) { + favoritesToolPanels.push_back(getFoldableToolPanel(tool)); + } + } + + int cur_page_num = toolPanelNotebook->get_current_page(); + Gtk::Widget *const cur_page = toolPanelNotebook->get_nth_page(cur_page_num); + + updatePanelTools(cur_page, favorites, cloneFavoriteTools); +} + bool ToolPanelCoordinator::handleShortcutKey(GdkEventKey* event) { @@ -1136,7 +1734,7 @@ bool ToolPanelCoordinator::handleShortcutKey(GdkEventKey* event) if (alt) { switch (event->keyval) { case GDK_KEY_u: - if (favoritePanelSW) { + if (toolPanelNotebook->page_num(*favoritePanelSW) >= 0) { toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*favoritePanelSW)); } return true; @@ -1182,9 +1780,7 @@ 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; - if (favoritePanelSW) { - favoritePanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); - } + favoritePanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); exposurePanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); detailsPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); colorPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); @@ -1216,7 +1812,7 @@ void ToolPanelCoordinator::toolSelected(ToolMode tool) 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) { + for (auto fav : favoritesToolPanels) { if (fav == tool) { return true; } @@ -1272,6 +1868,8 @@ void ToolPanelCoordinator::toolSelected(ToolMode tool) break; } + updateToolLocations(options.favorites, options.cloneFavoriteTools); + notebookconn.block(false); } @@ -1301,3 +1899,128 @@ bool ToolPanelCoordinator::getFilmNegativeSpot(rtengine::Coord spot, int spotSiz { return ipc && ipc->getFilmNegativeSpot(spot.x, spot.y, spotSize, refInput, refOutput); } + +FoldableToolPanel *ToolPanelCoordinator::getFoldableToolPanel(Tool tool) const +{ + switch (tool) { + case Tool::TONE_CURVE: + return toneCurve; + case Tool::SHADOWS_HIGHLIGHTS: + return shadowshighlights; + case Tool::IMPULSE_DENOISE: + return impulsedenoise; + case Tool::DEFRINGE_TOOL: + return defringe; + case Tool::SPOT: + return spot; + case Tool::DIR_PYR_DENOISE: + return dirpyrdenoise; + case Tool::EPD: + return epd; + case Tool::SHARPENING_TOOL: + return sharpening; + case Tool::LOCAL_CONTRAST: + return localContrast; + case Tool::SHARPEN_EDGE: + return sharpenEdge; + case Tool::SHARPEN_MICRO: + return sharpenMicro; + case Tool::L_CURVE: + return lcurve; + case Tool::RGB_CURVES: + return rgbcurves; + case Tool::COLOR_TONING: + return colortoning; + case Tool::LENS_GEOM: + return lensgeom; + case Tool::LENS_PROF: + return lensProf; + case Tool::DISTORTION: + return distortion; + case Tool::ROTATE: + return rotate; + case Tool::VIBRANCE: + return vibrance; + case Tool::COLOR_APPEARANCE: + return colorappearance; + case Tool::WHITE_BALANCE: + return whitebalance; + case Tool::VIGNETTING: + return vignetting; + case Tool::RETINEX_TOOL: + return retinex; + case Tool::GRADIENT: + return gradient; + case Tool::LOCALLAB: + return locallab; + case Tool::PC_VIGNETTE: + return pcvignette; + case Tool::PERSPECTIVE: + return perspective; + case Tool::CA_CORRECTION: + return cacorrection; + case Tool::CH_MIXER: + return chmixer; + case Tool::BLACK_WHITE: + return blackwhite; + case Tool::RESIZE_TOOL: + return resize; + case Tool::PR_SHARPENING: + return prsharpening; + case Tool::CROP_TOOL: + return crop; + case Tool::ICM: + return icm; + case Tool::WAVELET: + return wavelet; + case Tool::DIR_PYR_EQUALIZER: + return dirpyrequalizer; + case Tool::HSV_EQUALIZER: + return hsvequalizer; + case Tool::FILM_SIMULATION: + return filmSimulation; + case Tool::SOFT_LIGHT: + return softlight; + case Tool::DEHAZE: + return dehaze; + case Tool::SENSOR_BAYER: + return sensorbayer; + case Tool::SENSOR_XTRANS: + return sensorxtrans; + case Tool::BAYER_PROCESS: + return bayerprocess; + case Tool::XTRANS_PROCESS: + return xtransprocess; + case Tool::BAYER_PREPROCESS: + return bayerpreprocess; + case Tool::PREPROCESS: + return preprocess; + case Tool::DARKFRAME_TOOL: + return darkframe; + case Tool::FLATFIELD_TOOL: + return flatfield; + case Tool::RAW_CA_CORRECTION: + return rawcacorrection; + case Tool::RAW_EXPOSURE: + return rawexposure; + case Tool::PREPROCESS_WB: + return preprocessWB; + case Tool::BAYER_RAW_EXPOSURE: + return bayerrawexposure; + case Tool::XTRANS_RAW_EXPOSURE: + return xtransrawexposure; + case Tool::FATTAL: + return fattal; + case Tool::FILM_NEGATIVE: + return filmNegative; + case Tool::PD_SHARPENING: + return pdSharpening; + }; + assert(false); + return nullptr; +} + +FoldableToolPanel *ToolPanelCoordinator::getFoldableToolPanel(const ToolTree &toolTree) const +{ + return getFoldableToolPanel(toolTree.id); +} diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 031c43459..fcc470953 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -18,6 +18,7 @@ */ #pragma once +#include #include #include @@ -169,11 +170,13 @@ protected: FilmNegative* filmNegative; PdSharpening* pdSharpening; std::vector paramcListeners; + std::unordered_map + expanderToToolPanelMap; rtengine::StagedImageProcessor* ipc; std::vector toolPanels; - std::vector favorites; + std::vector favoritesToolPanels; ToolVBox* favoritePanel; ToolVBox* exposurePanel; ToolVBox* detailsPanel; @@ -184,7 +187,7 @@ protected: ToolVBox* locallabPanel; ToolBar* toolBar; - TextOrIcon* toiF; + std::unique_ptr toiF; TextOrIcon* toiE; TextOrIcon* toiD; TextOrIcon* toiC; @@ -197,7 +200,7 @@ protected: Gtk::Image* imgPanelEnd[8]; Gtk::Box* vbPanelEnd[8]; - Gtk::ScrolledWindow* favoritePanelSW; + std::unique_ptr favoritePanelSW; Gtk::ScrolledWindow* exposurePanelSW; Gtk::ScrolledWindow* detailsPanelSW; Gtk::ScrolledWindow* colorPanelSW; @@ -209,12 +212,17 @@ protected: std::vector expList; bool hasChanged; + bool batch; 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); + void updatePanelTools( + Gtk::Widget *page, + const std::vector &favorites, + bool cloneFavoriteTools); private: EditDataProvider *editDataProvider; @@ -224,12 +232,107 @@ private: Gtk::Widget* prevPage; public: + enum class Panel { + FAVORITE, + EXPOSURE, + DETAILS, + COLOR, + ADVANCED, + LOCALLAB, + TRANSFORM_PANEL, + RAW, + }; + + enum class Tool { + TONE_CURVE, + SHADOWS_HIGHLIGHTS, + IMPULSE_DENOISE, + DEFRINGE_TOOL, + SPOT, + DIR_PYR_DENOISE, + EPD, + SHARPENING_TOOL, + LOCAL_CONTRAST, + SHARPEN_EDGE, + SHARPEN_MICRO, + L_CURVE, + RGB_CURVES, + COLOR_TONING, + LENS_GEOM, + LENS_PROF, + DISTORTION, + ROTATE, + VIBRANCE, + COLOR_APPEARANCE, + WHITE_BALANCE, + VIGNETTING, + RETINEX_TOOL, + GRADIENT, + LOCALLAB, + PC_VIGNETTE, + PERSPECTIVE, + CA_CORRECTION, + CH_MIXER, + BLACK_WHITE, + RESIZE_TOOL, + PR_SHARPENING, + CROP_TOOL, + ICM, + WAVELET, + DIR_PYR_EQUALIZER, + HSV_EQUALIZER, + FILM_SIMULATION, + SOFT_LIGHT, + DEHAZE, + SENSOR_BAYER, + SENSOR_XTRANS, + BAYER_PROCESS, + XTRANS_PROCESS, + BAYER_PREPROCESS, + PREPROCESS, + DARKFRAME_TOOL, + FLATFIELD_TOOL, + RAW_CA_CORRECTION, + RAW_EXPOSURE, + PREPROCESS_WB, + BAYER_RAW_EXPOSURE, + XTRANS_RAW_EXPOSURE, + FATTAL, + FILM_NEGATIVE, + PD_SHARPENING, + }; + + struct ToolTree { + Tool id; + std::vector children; + }; + + using ToolLayout = std::unordered_map &, ScopedEnumHash>; + CoarsePanel* coarse; Gtk::Notebook* toolPanelNotebook; ToolPanelCoordinator(bool batch = false); ~ToolPanelCoordinator () override; + static const ToolLayout &getDefaultToolLayout(); + /** + * Gets the tool with the provided tool name. + * + * @param name The tool name as a raw string. + * @return The tool. + * @throws std::out_of_range If the name is not recognized. + */ + static Tool getToolFromName(const std::string &name); + /** + * Gets the tool name for the tool's ToolPanel as a string. + * + * @param tool The name as a raw string, or an empty string if the tool is + * unknown. + */ + static std::string getToolName(Tool tool); + static bool isFavoritable(Tool tool); + bool getChangedState() { return hasChanged; @@ -247,6 +350,8 @@ public: const LUTu& histLRETI ); void foldAllButOne(Gtk::Box* parent, FoldableToolPanel* openedSection); + void updateToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); // multiple listeners can be added that are notified on changes (typical: profile panel and the history) void addPParamsChangeListener(PParamsChangeListener* pp) @@ -261,7 +366,7 @@ public: void unsetTweakOperator (rtengine::TweakOperator *tOperator) override; // FilmNegProvider interface - void imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans, bool isMono = false) override; + void imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans, bool isMono = false, bool isGainMapSupported = false) override; // profilechangelistener interface void profileChange( @@ -354,6 +459,25 @@ public: void setEditProvider(EditDataProvider *provider); +protected: + static std::unordered_map toolNamesReverseMap; + + std::unordered_map + toolToDefaultToolTreeMap; + + FoldableToolPanel *getFoldableToolPanel(Tool tool) const; + FoldableToolPanel *getFoldableToolPanel(const ToolTree &tool) const; + void updateFavoritesPanel( + const std::vector &favorites, bool cloneFavoriteTools); + template + typename std::enable_if::value, void>::type + updateToolPanel( + Gtk::Box *panelBox, + const std::vector &children, + int level, + const std::unordered_set &favorites, + bool cloneFavoriteTools); + private: IdleRegister idle_register; }; diff --git a/rtgui/vibrance.cc b/rtgui/vibrance.cc index 4a9fab3d3..f2eb8fc4e 100644 --- a/rtgui/vibrance.cc +++ b/rtgui/vibrance.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Vibrance::Vibrance () : FoldableToolPanel(this, "vibrance", M("TP_VIBRANCE_LABEL"), false, true) +const Glib::ustring Vibrance::TOOL_NAME = "vibrance"; + +Vibrance::Vibrance () : FoldableToolPanel(this, TOOL_NAME, M("TP_VIBRANCE_LABEL"), false, true) { std::vector milestones; diff --git a/rtgui/vibrance.h b/rtgui/vibrance.h index 12acc7948..ee3d029ee 100644 --- a/rtgui/vibrance.h +++ b/rtgui/vibrance.h @@ -57,6 +57,7 @@ protected: sigc::connection pastsattogconn; public: + static const Glib::ustring TOOL_NAME; Vibrance (); ~Vibrance () override; diff --git a/rtgui/vignetting.cc b/rtgui/vignetting.cc index 04a350b99..c2652de42 100644 --- a/rtgui/vignetting.cc +++ b/rtgui/vignetting.cc @@ -23,7 +23,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Vignetting::Vignetting () : FoldableToolPanel(this, "vignetting", M("TP_VIGNETTING_LABEL")) +const Glib::ustring Vignetting::TOOL_NAME = "vignetting"; + +Vignetting::Vignetting () : FoldableToolPanel(this, TOOL_NAME, M("TP_VIGNETTING_LABEL")) { amount = Gtk::manage (new Adjuster (M("TP_VIGNETTING_AMOUNT"), -100, 100, 1, 0)); diff --git a/rtgui/vignetting.h b/rtgui/vignetting.h index be7765094..bcb7f9d19 100644 --- a/rtgui/vignetting.h +++ b/rtgui/vignetting.h @@ -37,6 +37,7 @@ protected: Adjuster* centerY; public: + static const Glib::ustring TOOL_NAME; Vignetting (); diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc index 1b8dd980c..c3ce7f6af 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -34,6 +34,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring Wavelet::TOOL_NAME = "wavelet"; + namespace { @@ -62,7 +64,7 @@ std::vector makeWholeHueRange() } Wavelet::Wavelet() : - FoldableToolPanel(this, "wavelet", M("TP_WAVELET_LABEL"), true, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_WAVELET_LABEL"), true, true), curveEditorG(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_CONTEDIT"))), //curveEditorC(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_CONTRASTEDIT"))), CCWcurveEditorG(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_CCURVE"))), diff --git a/rtgui/wavelet.h b/rtgui/wavelet.h index 0060520f6..a6814f374 100644 --- a/rtgui/wavelet.h +++ b/rtgui/wavelet.h @@ -45,6 +45,8 @@ class Wavelet final : public FoldableToolPanel { public: + static const Glib::ustring TOOL_NAME; + Wavelet(); ~Wavelet() override; bool wavComputed_(); diff --git a/rtgui/whitebalance.cc b/rtgui/whitebalance.cc index e1e3af22a..bf980287f 100644 --- a/rtgui/whitebalance.cc +++ b/rtgui/whitebalance.cc @@ -34,6 +34,7 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring WhiteBalance::TOOL_NAME = "whitebalance"; static double wbSlider2Temp(double sval) { @@ -117,7 +118,7 @@ static double wbTemp2Slider(double temp) return sval; } -WhiteBalance::WhiteBalance () : FoldableToolPanel(this, "whitebalance", M("TP_WBALANCE_LABEL"), true, true), wbp(nullptr), wblistener(nullptr) +WhiteBalance::WhiteBalance () : FoldableToolPanel(this, TOOL_NAME, M("TP_WBALANCE_LABEL"), true, true), wbp(nullptr), wblistener(nullptr) { // Assign icon name to wbIcons wbIcons[toUnderlying(WBEntry::Type::CAMERA)] = "wb-camera-small"; diff --git a/rtgui/whitebalance.h b/rtgui/whitebalance.h index a034c1686..5a3b32bb3 100644 --- a/rtgui/whitebalance.h +++ b/rtgui/whitebalance.h @@ -98,6 +98,7 @@ protected: std::pair findWBEntry (const Glib::ustring& label, enum WB_LabelType lblType = WBLT_GUI); public: + static const Glib::ustring TOOL_NAME; WhiteBalance (); ~WhiteBalance () override; diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 89fd0f8a4..d6850da63 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar) +const Glib::ustring XTransProcess::TOOL_NAME = "xtransprocess"; + +XTransProcess::XTransProcess () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar) { auto m = ProcEventMapper::getInstance(); EvDemosaicBorder = m->newEvent(DEMOSAIC, "HISTORY_MSG_RAW_BORDER"); diff --git a/rtgui/xtransprocess.h b/rtgui/xtransprocess.h index 4725f4a6d..6639a3796 100644 --- a/rtgui/xtransprocess.h +++ b/rtgui/xtransprocess.h @@ -52,6 +52,7 @@ protected: rtengine::ProcEvent EvDemosaicContrast; public: + static const Glib::ustring TOOL_NAME; XTransProcess (); ~XTransProcess () override; diff --git a/rtgui/xtransrawexposure.cc b/rtgui/xtransrawexposure.cc index e1b56b9f0..2e26b8f63 100644 --- a/rtgui/xtransrawexposure.cc +++ b/rtgui/xtransrawexposure.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -XTransRAWExposure::XTransRAWExposure () : FoldableToolPanel(this, "xtransrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL")) +const Glib::ustring XTransRAWExposure::TOOL_NAME = "xtransrawexposure"; + +XTransRAWExposure::XTransRAWExposure () : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOS_BLACKPOINT_LABEL")) { PexBlackRed = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_RED"), -2048, 2048, 1.0, 0)); //black level PexBlackRed->setAdjusterListener (this); diff --git a/rtgui/xtransrawexposure.h b/rtgui/xtransrawexposure.h index a8daf6972..c332bc510 100644 --- a/rtgui/xtransrawexposure.h +++ b/rtgui/xtransrawexposure.h @@ -37,6 +37,7 @@ protected: private: // Gtk::CheckButton* PextwoGreen; public: + static const Glib::ustring TOOL_NAME; XTransRAWExposure (); diff --git a/tools/osx/libiconv_1.16_rt.patch b/tools/osx/libiconv_1.16_rt.patch deleted file mode 100644 index 470f7780c..000000000 --- a/tools/osx/libiconv_1.16_rt.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git a/lib/iconv.c b/lib/iconv.c -index b7a04f8..41c5896 100644 ---- a/lib/iconv.c -+++ b/lib/iconv.c -@@ -610,5 +610,26 @@ strong_alias (libiconv_open, iconv_open) - strong_alias (libiconv, iconv) - strong_alias (libiconv_close, iconv_close) - #endif -+ -+#undef iconv_open -+#undef iconv -+#undef iconv_close -+ -+LIBICONV_DLL_EXPORTED iconv_t iconv_open (const char* tocode, const char* fromcode) -+{ -+ return libiconv_open(tocode, fromcode); -+} -+ -+LIBICONV_DLL_EXPORTED size_t iconv (iconv_t icd, -+ ICONV_CONST char * * inbuf, size_t *inbytesleft, -+ char * * outbuf, size_t *outbytesleft) -+{ -+ return libiconv(icd, inbuf, inbytesleft, outbuf, outbytesleft); -+} -+ -+LIBICONV_DLL_EXPORTED int iconv_close (iconv_t icd) -+{ -+ return libiconv_close(icd); -+} - - #endif diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index d0cbf4d6b..ca381ec14 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -9,11 +9,11 @@ # - GTK_PREFIX # Formatting -fNormal="$(tput sgr0)" -fBold="$(tput bold)" +fNormal="$(tput sgr0)" >/dev/null 2>&1 +fBold="$(tput bold)" >/dev/null 2>&1 # Colors depend upon the user's terminal emulator color scheme - what is readable for you may be not readable for someone else. -fMagenta="$(tput setaf 5)" -fRed="$(tput setaf 1)" +fMagenta="$(tput setaf 5)" >/dev/null 2>&1 +fRed="$(tput setaf 1)" >/dev/null 2>&1 function msg { printf "\\n${fBold}-- %s${fNormal}\\n" "${@}" @@ -120,8 +120,8 @@ minimum_macos_version=${MINIMUM_SYSTEM_VERSION} #Out: /opt LOCAL_PREFIX="$(cmake .. -L -N | grep LOCAL_PREFIX)"; LOCAL_PREFIX="${LOCAL_PREFIX#*=}" -#In: OSX_UNIVERSAL_URL=https:// etc. -#Out: https:// etc. +#In: OSX_UNIVERSAL_URL=file:/// etc. +#Out: file:/// etc. UNIVERSAL_URL="$(cmake .. -L -N | grep OSX_UNIVERSAL_URL)"; UNIVERSAL_URL="${UNIVERSAL_URL#*=}" if [[ -n $UNIVERSAL_URL ]]; then echo "Universal app is ON. The URL is ${UNIVERSAL_URL}" @@ -135,8 +135,8 @@ EXPATLIB="$(cmake .. -LA -N | grep pkgcfg_lib_EXPAT_expat)"; pkgcfg_lib_EXPAT_ex #Out: Developer ID Application: Doctor Who (1234567890) CODESIGNID="$(cmake .. -L -N | grep CODESIGNID)"; CODESIGNID="${CODESIGNID#*=}" -#In: NOTARY:STRING=--username drwho@bbc.com --password abcd-efgh-hijk-lmno -#Out: --username drwho@bbc.com --password abcd-efgh-hijk-lmno +#In: NOTARY:STRING="--apple-id drwho@bbc.com --password abcd-efgh-hijk-lmno --team-id ABCDE12345" +#Out: --apple-id drwho@bbc.com --password abcd-efgh-hijk-lmno --team-id ABCDE12345 NOTARY="$(cmake .. -L -N | grep NOTARY)"; NOTARY="${NOTARY#*=}" # In: FANCY_DMG:BOOL=ON @@ -153,6 +153,13 @@ if [[ -n $NIGHTLY ]]; then echo "Nightly/generically-named zip is ON." fi +# In: OSX_CONTINUOUS:BOOL=ON +# Out: ON +OSX_CONTINUOUS="$(cmake .. -L -N | grep OSX_CONTINUOUS)"; NIGHTLY="${OSX_CONTINUOUS#*=}" && CONTINUOUS="${OSX_CONTINUOUS#*=}" +if [[ -n $CONTINUOUS ]]; then + echo "Continuous/generically-named zip is ON." +fi + APP="${PROJECT_NAME}.app" CONTENTS="${APP}/Contents" RESOURCES="${CONTENTS}/Resources" @@ -191,15 +198,17 @@ lensfunversion=$(pkg-config --modversion lensfun | cut -f3 -d'.') if [ $lensfunversion = 95 ] then ditto ${LOCAL_PREFIX}/share/lensfun/version_2/* "${RESOURCES}/share/lensfun" + # Copy liblensfun to Frameworks + ditto ${LOCAL_PREFIX}/lib/liblensfun.2.dylib "${CONTENTS}/Frameworks/liblensfun.2.dylib" + else ditto ${LOCAL_PREFIX}/share/lensfun/version_1/* "${RESOURCES}/share/lensfun" + # Copy liblensfun to Frameworks + ditto ${LOCAL_PREFIX}/lib/liblensfun.1.dylib "${CONTENTS}/Frameworks/liblensfun.1.dylib" fi -# Copy liblensfun to Frameworks -ditto ${LOCAL_PREFIX}/lib/liblensfun.2.dylib "${CONTENTS}/Frameworks/liblensfun.2.dylib" - # Copy libomp to Frameworks -ditto ${LOCAL_PREFIX}/lib/libomp.dylib "${CONTENTS}/Frameworks" +cp ${LOCAL_PREFIX}/lib/libomp.dylib "${CONTENTS}/Frameworks" msg "Copying dependencies from ${GTK_PREFIX}." CheckLink "${EXECUTABLE}" 2>&1 @@ -207,24 +216,20 @@ CheckLink "${EXECUTABLE}" 2>&1 # dylib install names ModifyInstallNames 2>&1 -# Copy libjpeg-turbo ("62") into the app bundle -ditto ${LOCAL_PREFIX}/lib/libjpeg.62.dylib "${CONTENTS}/Frameworks/libjpeg.62.dylib" +## Copy libexpat into the app bundle (which is keg-only) +## if [[ -d /usr/local/Cellar/expat ]]; then ditto /usr/local/Cellar/expat/*/lib/libexpat.1.dylib "${CONTENTS}/Frameworks"; else cp "${EXPATLIB}" "${CONTENTS}/Frameworks/libexpat.1.dylib"; fi -# Copy libexpat into the app bundle (which is keg-only) -if [[ -d /usr/local/Cellar/expat ]]; then ditto /usr/local/Cellar/expat/*/lib/libexpat.1.dylib "${CONTENTS}/Frameworks"; else ditto "${EXPATLIB}" "${CONTENTS}/Frameworks/libexpat.1.dylib"; fi +## Copy libz into the app bundle +## cp ${LOCAL_PREFIX}/lib/libz.1.dylib "${CONTENTS}/Frameworks" -# Copy libz into the app bundle -ditto ${LOCAL_PREFIX}/lib/libz.1.dylib "${CONTENTS}/Frameworks" - -# Copy libpng12 & 16 to the app bundle -ditto ${LOCAL_PREFIX}/lib/libpng16.16.dylib "${CONTENTS}/Frameworks/libpng16.16.dylib" -ditto ${LOCAL_PREFIX}/lib/libpng12.0.dylib "${CONTENTS}/Frameworks/libpng12.0.dylib" +# Copy libpng16 to the app bundle +cp ${LOCAL_PREFIX}/lib/libpng16.16.dylib "${CONTENTS}/Frameworks/libpng16.16.dylib" # Copy libtiff 5 into the app bundle -ditto ${LOCAL_PREFIX}/lib/libtiff.5.dylib "${CONTENTS}/Frameworks/libtiff.5.dylib" +cp ${LOCAL_PREFIX}/lib/libtiff.5.dylib "${CONTENTS}/Frameworks/libtiff.5.dylib" # Copy libomp to Frameworks -ditto ${LOCAL_PREFIX}/lib/libomp.dylib "${CONTENTS}/Frameworks" +cp ${LOCAL_PREFIX}/lib/libomp.dylib "${CONTENTS}/Frameworks" # Prepare GTK+3 installation msg "Copying configuration files from ${GTK_PREFIX}:" @@ -238,7 +243,7 @@ find -E "${LIB}" -type f -regex '.*\.(a|la|cache)$' | while read -r; do rm "${RE # Make Frameworks folder flat msg "Flattening the Frameworks folder" cp -RL "${LIB}"/gdk-pixbuf-2.0/2*/loaders/* "${LIB}" -cp "${LIB}"/gtk-3.0/3*/immodules/*.{dylib,so} "${LIB}" +cp "${LIB}"/gtk-3.0/3*/immodules/*.{dylib,so} "${LIB}" >/dev/null 2>&1 rm -r "${LIB}"/gtk-3.0 rm -r "${LIB}"/gdk-pixbuf-2.0 @@ -368,27 +373,7 @@ if [[ -n $NOTARY ]]; then msg "Notarizing the application:" ditto -c -k --sequesterRsrc --keepParent "${APP}" "${APP}.zip" echo "Uploading..." - uuid=`xcrun altool --notarize-app --primary-bundle-id "com.rawtherapee.RawTherapee" ${NOTARY} --file "${APP}.zip" 2>&1 | grep 'RequestUUID' | awk '{ print $3 }'` - echo "Result= $uuid" # Display identifier string - sleep 15 - while : - do - fullstatus=`xcrun altool --notarization-info "$uuid" ${NOTARY} 2>&1` # get the status - status1=`echo "$fullstatus" | grep 'Status\:' | awk '{ print $2 }'` - if [[ $status1 = "success" ]]; then - xcrun stapler staple *app # staple the ticket - xcrun stapler validate -v *app - echo "Notarization success" - break - elif [[ $status1 = "in" ]]; then - echo "Notarization still in progress, sleeping for 15 seconds and trying again" - sleep 15 - else - echo "Notarization failed fullstatus below" - echo "$fullstatus" - exit 1 - fi - done + sudo xcrun notarytool submit "${APP}.zip" ${NOTARY} --wait fi function CreateDmg { @@ -450,39 +435,26 @@ function CreateDmg { msg "Notarizing the dmg:" zip "${dmg_name}.dmg.zip" "${dmg_name}.dmg" echo "Uploading..." - uuid=$(xcrun altool --notarize-app --primary-bundle-id "com.rawtherapee" ${NOTARY} --file "${dmg_name}.dmg.zip" 2>&1 | grep 'RequestUUID' | awk '{ print $3 }') - echo "dmg Result= ${uuid}" # Display identifier string - sleep 15 - while : - do - fullstatus=`xcrun altool --notarization-info "$uuid" ${NOTARY} 2>&1` # get the status - status1=`echo "$fullstatus" | grep 'Status\:' | awk '{ print $2 }'` - if [[ $status1 = "success" ]]; then - xcrun stapler staple "${dmg_name}.dmg" # staple the ticket - xcrun stapler validate -v "${dmg_name}.dmg" - echo "dmg Notarization success" - rm *dmg.zip - break - elif [[ $status1 = "in" ]]; then - echo "dmg Notarization still in progress, sleeping for 15 seconds and trying again" - sleep 15 - else - echo "dmg Notarization failed fullstatus below" - echo "$fullstatus" - exit 1 - fi - done + sudo xcrun notarytool submit "${dmg_name}.dmg.zip" ${NOTARY} --wait fi # Zip disk image for redistribution msg "Zipping disk image for redistribution:" mkdir "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}_folder" - ditto {"${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.dmg","rawtherapee-cli","${PROJECT_SOURCE_DATA_DIR}/INSTALL.txt"} "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}_folder" + cp {"${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.dmg","${PROJECT_NAME}.app/Contents/Frameworks/rawtherapee-cli","${PROJECT_SOURCE_DATA_DIR}/INSTALL.readme.rtf"} "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}_folder" zip -r "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.zip" "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}_folder/" if [[ -n $NIGHTLY ]]; then cp "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.zip" "${PROJECT_NAME}_macOS_${arch}_latest.zip" fi + if [[ -n $CONTINUOUS ]]; then + BRANCH=$(git branch --show-current) + if test -z "${BRANCH}"; then + BRANCH=$(git rev-parse --short HEAD) + fi + mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_${BRANCH}_macOS_${CMAKE_BUILD_TYPE}.zip" + fi } + CreateDmg msg "Finishing build:" echo "Script complete."