diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index cc0d16b8f..9ad9a6cbd 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -10,9 +10,11 @@ on: branches: - dev workflow_dispatch: +env: + publish_pre_dev_labels: '[]' jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: @@ -167,3 +169,33 @@ jobs: files: | ${{env.PUBLISH_NAME}}.AppImage ${{env.PUBLISH_NAME}}-AboutThisBuild.txt + + - name: Prepare for publishing pre-dev + id: prepare-publish-pre-dev + if: ${{github.event_name == 'pull_request' && contains(fromJSON(env.publish_pre_dev_labels), github.event.pull_request.head.label)}} + run: | + echo "Making ref name." + REF_NAME_FILTERED="$(echo '${{github.event.pull_request.head.label}}' | tr ':' '_' | sed 's/[^A-z0-9_.-]//g')" + echo "Ref name is '$REF_NAME_FILTERED'." + + echo "Setting publish name." + PUBLISH_NAME="RawTherapee_${REF_NAME_FILTERED}_${{matrix.build_type}}" + echo "Publish name is '$PUBLISH_NAME'." + + echo "Renaming AppImage." + cp "build/$ARTIFACT_NAME.AppImage" "$PUBLISH_NAME.AppImage" + + echo "Creating version file." + cp "build/AboutThisBuild.txt" "$PUBLISH_NAME-AppImage-AboutThisBuild.txt" + + echo "Recording publish name." + echo "PUBLISH_NAME=$PUBLISH_NAME" >> $GITHUB_ENV + + - name: Publish pre-dev artifacts + uses: softprops/action-gh-release@v1 + if: ${{steps.prepare-publish-pre-dev.outcome == 'success'}} + with: + tag_name: pre-dev-github-actions + files: | + ${{env.PUBLISH_NAME}}.AppImage + ${{env.PUBLISH_NAME}}-AppImage-AboutThisBuild.txt diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 11ae28aa4..3348d48b9 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -14,7 +14,7 @@ jobs: build: runs-on: macos-11 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install dependencies run: | date -u @@ -48,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 \ @@ -61,9 +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 libomp.rb + 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: | @@ -77,7 +79,7 @@ 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 @@ -91,7 +93,7 @@ jobs: "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}} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ab81edec6..4ab10212c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -10,6 +10,8 @@ on: branches: - dev workflow_dispatch: +env: + publish_pre_dev_labels: '[]' jobs: build: runs-on: windows-2022 @@ -94,6 +96,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'." @@ -120,6 +124,7 @@ jobs: "libexpat-1.dll" \ libffi-*.dll \ "libfftw3f-3.dll" \ + "libfftw3f_omp-3.dll" \ "libfontconfig-1.dll" \ "libfreetype-6.dll" \ "libfribidi-0.dll" \ @@ -173,15 +178,15 @@ jobs: echo "Copying Adwaita theme." mkdir -p "$BUILD_DIR/share/icons/Adwaita" cd 'share/icons/Adwaita/' - mkdir -p "$BUILD_DIR/share/icons/Adwaita/scalable" + mkdir -p "$BUILD_DIR/share/icons/Adwaita/symbolic" cp -r \ - "scalable/actions" \ - "scalable/devices" \ - "scalable/mimetypes" \ - "scalable/places" \ - "scalable/status" \ - "scalable/ui" \ - "$BUILD_DIR/share/icons/Adwaita/scalable" + "symbolic/actions" \ + "symbolic/devices" \ + "symbolic/mimetypes" \ + "symbolic/places" \ + "symbolic/status" \ + "symbolic/ui" \ + "$BUILD_DIR/share/icons/Adwaita/symbolic" cp 'index.theme' "$BUILD_DIR/share/icons/Adwaita" mkdir -p "$BUILD_DIR/share/icons/Adwaita/cursors" cp -r \ @@ -203,7 +208,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')}} @@ -297,3 +302,44 @@ jobs: with: tag_name: nightly-github-actions files: build/${{env.PUBLISH_NAME}}.exe + + - name: Prepare for publishing pre-dev + id: prepare-publish-pre-dev + if: ${{github.event_name == 'pull_request' && contains(fromJSON(env.publish_pre_dev_labels), github.event.pull_request.head.label)}} + run: | + echo "Making ref name." + REF_NAME_FILTERED="$(echo '${{github.event.pull_request.head.label}}' | tr ':' '_' | sed 's/[^A-z0-9_.-]//g')" + echo "Ref name is '$REF_NAME_FILTERED'." + + echo "Setting publish name." + PUBLISH_NAME="RawTherapee_${REF_NAME_FILTERED}_win64_${{matrix.build_type}}" + echo "Publish name is '$PUBLISH_NAME'." + if [ "$ARTIFACT_NAME" != "$PUBLISH_NAME" ]; then + echo "Renaming ZIP file." + cp "build/$ARTIFACT_NAME.zip" "build/$PUBLISH_NAME.zip" + if [ -e "./build/$ARTIFACT_NAME.exe" ]; then + echo "Renaming installer." + mv "./build/$ARTIFACT_NAME.exe" "./build/$PUBLISH_NAME.exe" + fi + fi + echo "Creating version file." + cp "build/$ARTIFACT_NAME/AboutThisBuild.txt" "build/$PUBLISH_NAME-AboutThisBuild.txt" + + echo "Recording publish name." + echo "PUBLISH_NAME=$PUBLISH_NAME" >> "$(cygpath -u $GITHUB_ENV)" + + - name: Publish pre-dev artifacts + uses: softprops/action-gh-release@v1 + if: ${{steps.prepare-publish-pre-dev.outcome == 'success'}} + with: + tag_name: pre-dev-github-actions + files: | + build/${{env.PUBLISH_NAME}}.zip + build/${{env.PUBLISH_NAME}}-AboutThisBuild.txt + + - name: Publish pre-dev installer + uses: softprops/action-gh-release@v1 + if: ${{steps.prepare-publish-pre-dev.outcome == 'success' && matrix.build_type == 'release'}} + with: + tag_name: pre-dev-github-actions + files: build/${{env.PUBLISH_NAME}}.exe diff --git a/AUTHORS.txt b/AUTHORS.txt index 4fb664fa5..374a7935b 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -5,6 +5,7 @@ Project initiator: Development contributors, in last name alphabetical order: + Harald Aust Roel Baars Richard E Barber Martin Burri diff --git a/CMakeLists.txt b/CMakeLists.txt index 30e646fd8..92888424c 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 21f219a83..64f4d08aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -![RawTherapee logo](https://raw.githubusercontent.com/Beep6581/RawTherapee/dev/rtdata/images/rt-logo-text-black.svg) + + + + RawTherapee logo + ![RawTherapee screenshot](http://rawtherapee.com/images/carousel/100_rt59_provence_local_maskxxx.jpg) diff --git a/rtdata/languages/default b/rtdata/languages/default index 5ef9d310b..74f17098f 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1417,6 +1417,7 @@ 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 @@ -1533,6 +1534,7 @@ HISTORY_MSG_WAVSTREND;Strength soft HISTORY_MSG_WAVTHRDEN;Threshold local contrast HISTORY_MSG_WAVTHREND;Threshold local contrast HISTORY_MSG_WAVUSHAMET;Clarity method +HISTORY_MSG_WBALANCE_OBSERVER10;Observer 10° HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1829,6 +1831,7 @@ PREFERENCES_CACHECLEAR_SAFETY;Only files in the cache are cleared. Processing pr PREFERENCES_CACHEMAXENTRIES;Maximum number of cache entries PREFERENCES_CACHEOPTS;Cache Options PREFERENCES_CACHETHUMBHEIGHT;Maximum thumbnail height +PREFERENCES_CAMERAPROFILESDIR;Camera profiles directory PREFERENCES_CHUNKSIZES;Tiles per thread PREFERENCES_CHUNKSIZE_RAW_AMAZE;AMaZE demosaic PREFERENCES_CHUNKSIZE_RAW_CA;Raw CA correction @@ -1837,6 +1840,7 @@ PREFERENCES_CHUNKSIZE_RAW_XT;Xtrans demosaic PREFERENCES_CHUNKSIZE_RGB;RGB processing PREFERENCES_CIE;Ciecam PREFERENCES_CIEARTIF;Avoid artifacts +PREFERENCES_WBA;White Balance PREFERENCES_CLIPPINGIND;Clipping Indication PREFERENCES_CLUTSCACHE;HaldCLUT Cache PREFERENCES_CLUTSCACHE_LABEL;Maximum number of cached CLUTs @@ -1915,6 +1919,7 @@ PREFERENCES_INTENT_SATURATION;Saturation PREFERENCES_INTERNALTHUMBIFUNTOUCHED;Show embedded JPEG thumbnail if raw is unedited PREFERENCES_LANG;Language PREFERENCES_LANGAUTODETECT;Use system language +PREFERENCES_LENSPROFILESDIR;Lens profiles directory PREFERENCES_MAXRECENTFOLDERS;Maximum number of recent folders PREFERENCES_MENUGROUPEXTPROGS;Group 'Open with' PREFERENCES_MENUGROUPFILEOPERATIONS;Group 'File operations' @@ -2067,6 +2072,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 @@ -2209,7 +2215,8 @@ TP_COLORAPP_CHROMA_M_TOOLTIP;Colorfulness in CIECAM is the perceived amount of h TP_COLORAPP_CHROMA_S;Saturation (S) TP_COLORAPP_CHROMA_S_TOOLTIP;Saturation in CIECAM corresponds to the color of a stimulus in relation to its own brightness. It differs from L*a*b* and RGB saturation. TP_COLORAPP_CHROMA_TOOLTIP;Chroma in CIECAM corresponds to the color of a stimulus relative to the clarity of a stimulus that appears white under identical conditions. It differs from L*a*b* and RGB chroma. -TP_COLORAPP_CIECAT_DEGREE;Adaptation +TP_COLORAPP_CIECAT_DEGREE;Chromatic Adaptation Scene +TP_COLORAPP_CIECAT_DEGREEOUT;Chromatic Adaptation Viewing TP_COLORAPP_CONTRAST;Contrast (J) TP_COLORAPP_CONTRAST_Q;Contrast (Q) TP_COLORAPP_CONTRAST_Q_TOOLTIP;Contrast (Q) in CIECAM is based on brightness. It differs from L*a*b* and RGB contrast. @@ -2525,8 +2532,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: @@ -4093,6 +4102,10 @@ TP_WBALANCE_LED_CRS;CRS SP12 WWMR16 TP_WBALANCE_LED_HEADER;LED TP_WBALANCE_LED_LSI;LSI Lumelex 2040 TP_WBALANCE_METHOD;Method +TP_WBALANCE_MULLABEL;Multipliers: r=%1 g=%2 b=%3 +TP_WBALANCE_MULLABEL_TOOLTIP;Values given for information purposes. You cannot change them. +TP_WBALANCE_OBSERVER10;Observer 10° instead of Observer 2° +TP_WBALANCE_OBSERVER10_TOOLTIP;The color management in Rawtherapee (White balance, channel multipliers, highlight recovery,...) uses the spectral data of the illuminants and colors. Observer is an important parameter of this management which takes into account the angle of perception of the eye. In 1931 it was fixed at 2° (privileges the use of the cones). In 1964 it was fixed at 10° (privileges the use of the cones, but partially takes into account the rods).\nTo avoid a (rare) drift of the colors due to the choice Observer 10° - probably due to the conversion matrix - Observer 2° must be selected.\nIn a majority of cases Observer 10° (default) will be a more relevant choice. TP_WBALANCE_PICKER;Pick TP_WBALANCE_SHADE;Shade TP_WBALANCE_SIZE;Size: 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/rtengine/camconst.cc b/rtengine/camconst.cc index 64fc4d4ba..5cb56b2ae 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -224,7 +224,7 @@ CameraConst* CameraConst::parseEntry(const void *cJSON_, const char *make_model) const auto get_masked_areas = [](int w, int h, const cJSON *ji, CameraConst *cc) -> bool { - std::array, 2> rm; + std::array, 2> rm = {}; if (ji->type != cJSON_Array) { //fprintf(stderr, "\"masked_areas\" must be an array\n"); @@ -505,7 +505,15 @@ bool CameraConst::has_rawMask(int raw_width, int raw_height, int idx) const return false; } - 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(); + 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()) { + return (it->second[idx][0] | it->second[idx][1] | it->second[idx][2] | it->second[idx][3]) != 0; + } else { + return false; + } } diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 7a143e850..ac3980bbe 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1973,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 @@ -2170,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 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/colortemp.cc b/rtengine/colortemp.cc index a4dd8a4d1..756fdf906 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -33,7 +33,7 @@ namespace rtengine { -static 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 double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Desmis 2 }; -static const 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}, @@ -171,7 +171,7 @@ static const double cie_colour_match_jd[97][3] = {//350nm to 830nm 5 nm J.Desm -ColorTemp::ColorTemp (double t, double g, double e, const std::string &m) : temp(t), green(g), equal(e), method(m) +ColorTemp::ColorTemp (double t, double g, double e, const std::string &m, StandardObserver o) : temp(t), green(g), equal(e), method(m), observer(o) { clip (temp, green, equal); } @@ -189,12 +189,24 @@ void ColorTemp::clip (double &temp, double &green, double &equal) equal = rtengine::LIM(equal, MINEQUAL, MAXEQUAL); } -ColorTemp::ColorTemp (double mulr, double mulg, double mulb, double e) : equal(e), method("Custom") +ColorTemp::ColorTemp (double mulr, double mulg, double mulb, double e, StandardObserver observer) : equal(e), method("Custom"), observer(observer) { - mul2temp (mulr, mulg, mulb, equal, temp, green); + mul2temp (mulr, mulg, mulb, equal, observer, temp, green); } -void ColorTemp::mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green) const +ColorTemp ColorTemp::convertObserver(StandardObserver observer) const +{ + if (observer == this->observer) { + return *this; + } + double r; + double g; + double b; + getMultipliers(r, g, b); + return ColorTemp(r, g, b, equal, observer); +} + +void ColorTemp::mul2temp (const double rmul, const double gmul, const double bmul, const double equal, StandardObserver observer, double& temp, double& green) const { double maxtemp = MAXTEMP, mintemp = MINTEMP; @@ -202,7 +214,7 @@ void ColorTemp::mul2temp (const double rmul, const double gmul, const double bmu temp = (maxtemp + mintemp) / 2; while (maxtemp - mintemp > 1) { - temp2mul (temp, 1.0, equal, tmpr, tmpg, tmpb); + temp2mul (temp, 1.0, equal, observer, tmpr, tmpg, tmpb); if (tmpb / tmpr > bmul / rmul) { maxtemp = temp; @@ -2957,21 +2969,27 @@ void ColorTemp::icieCAT02float(float Xw, float Yw, float Zw, float &iCAM02BB00, } -void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxyz, double &Zxyz) +void ColorTemp::temp2mulxyz (double temp, const std::string &method, StandardObserver observer, double &Xxyz, double &Zxyz) { double x, y, z; // We first test for specially handled methods const auto iterator = spectMap.find(method); - + const auto &color_match = (observer == StandardObserver::TEN_DEGREES) ? cie_colour_match_jd : cie_colour_match_jd2; +/* if(observer == StandardObserver::TEN_DEGREES){ + printf("General Observer 10°\n"); + } else { + printf("General Observer 2°\n"); + } +*/ 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 +3008,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); } } @@ -2998,11 +3016,11 @@ void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxy Zxyz = (1.0 - x - y) / y; } -void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul, double& gmul, double& bmul) const +void ColorTemp::temp2mul (double temp, double green, double equal, StandardObserver observer, double& rmul, double& gmul, double& bmul) const { clip(temp, green, equal); double Xwb, Zwb; - temp2mulxyz(temp, method, Xwb, Zwb); + temp2mulxyz(temp, method, observer, Xwb, Zwb); double adj = 1.0; @@ -3169,17 +3187,25 @@ 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 = (observer == StandardObserver::TEN_DEGREES) ? cie_colour_match_jd : cie_colour_match_jd2; + //exceptional must be used by advice people + if(observer == StandardObserver::TEN_DEGREES){ + printf("CRI Observer 10°\n"); + } else { + printf("CRI Observer 2°\n"); + } + 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 +3223,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) { @@ -3394,16 +3420,16 @@ 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_jd2[i][0]; - Y += Me * cie_colour_match_jd2[i][1]; - Z += Me * cie_colour_match_jd2[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 +3438,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_jd2[i][0]; - Y += Me * cie_colour_match_jd2[i][1]; - Z += Me * cie_colour_match_jd2[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 +3456,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; @@ -3454,9 +3480,9 @@ void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, dou */ for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = get_spectral_color(lambda, spec_intens); - X += Me * cie_colour_match_jd2[i][0]; - Y += Me * cie_colour_match_jd2[i][1]; - Z += Me * cie_colour_match_jd2[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 +3492,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 +3504,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_jd2[i][0] * Me; - Y += Mc * cie_colour_match_jd2[i][1] * Me; - Z += Mc * cie_colour_match_jd2[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 +3514,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_jd2[i][1] * Ms; + Yo += color_match[i][1] * Ms; } xx = X / Yo; @@ -3497,7 +3523,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 +3531,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_jd2[i][0] * Me; - Y += Mc * cie_colour_match_jd2[i][1] * Me; - Z += Mc * cie_colour_match_jd2[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 +3542,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 +3550,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_jd2[i][0] * Me; - Y += Mc * cie_colour_match_jd2[i][1] * Me; - Z += Mc * cie_colour_match_jd2[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 +3787,16 @@ 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) { - printf("Use standard observer 2°\n"); - } else { - printf("Use standard observer 10°\n"); - } - } - - if (settings->itcwb_stdobserver10 == true) { - for (int i = 0; i < 97; i++) { - cie_colour_match_jd2[i][0] = cie_colour_match_jd[i][0]; - cie_colour_match_jd2[i][1] = cie_colour_match_jd[i][1];; - cie_colour_match_jd2[i][2] = cie_colour_match_jd[i][2]; - } - } + const color_match_type &color_match = (wbpar.observer == StandardObserver::TEN_DEGREES) ? cie_colour_match_jd : cie_colour_match_jd2; + + // const color_match_type &color_match = (wbpar.observer == StandardObserver::TEN_DEGREES) ? 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 +3815,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 +3824,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 +3843,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..0fe56b7cd 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; @@ -34,6 +36,10 @@ constexpr double MINEQUAL = 0.8; constexpr double MAXEQUAL = 1.5; constexpr double INITIALBLACKBODY = 4000.0; +enum class StandardObserver { + TWO_DEGREES, + TEN_DEGREES, +}; class ColorTemp { @@ -43,32 +49,36 @@ private: double green; double equal; std::string method; + StandardObserver observer{StandardObserver::TEN_DEGREES}; static void clip (double &temp, double &green); static void clip (double &temp, double &green, double &equal); int XYZtoCorColorTemp(double x0, double y0 , double z0, double &temp) const; - void temp2mul (double temp, double green, double equal, double& rmul, double& gmul, double& bmul) const; + void temp2mul (double temp, double green, double equal, StandardObserver observer, double& rmul, double& gmul, double& bmul) const; const static std::map spectMap; public: + static constexpr StandardObserver DEFAULT_OBSERVER = StandardObserver::TEN_DEGREES; ColorTemp () : temp(-1.), green(-1.), equal (1.), method("Custom") {} explicit ColorTemp (double e) : temp(-1.), green(-1.), equal (e), method("Custom") {} - ColorTemp (double t, double g, double e, const std::string &m); - ColorTemp (double mulr, double mulg, double mulb, double e); + ColorTemp (double t, double g, double e, const std::string &m, StandardObserver o); + ColorTemp (double mulr, double mulg, double mulb, double e, StandardObserver observer); static void tempxy(bool separated, int repref, float **Tx, float **Ty, float **Tz, float **Ta, float **Tb, float **TL, double *TX, double *TY, double *TZ, const procparams::WBParams & wbpar); - void update (const double rmul, const double gmul, const double bmul, const double equal, const double tempBias=0.0) + void update (const double rmul, const double gmul, const double bmul, const double equal, StandardObserver observer, const double tempBias=0.0) { this->equal = equal; - mul2temp (rmul, gmul, bmul, this->equal, temp, green); + this->observer = observer; + mul2temp (rmul, gmul, bmul, this->equal, observer, temp, green); if (tempBias != 0.0 && tempBias >= -1.0 && tempBias <= 1.0) { temp += temp * tempBias; } } - void useDefaults (const double equal) + void useDefaults (const double equal, StandardObserver observer) { temp = 6504; // Values copied from procparams.cc green = 1.0; this->equal = equal; + this->observer = observer; } inline std::string getMethod() const @@ -87,14 +97,20 @@ public: { return equal; } + inline StandardObserver getObserver() const + { + return observer; + } + + ColorTemp convertObserver(StandardObserver observer) const; void getMultipliers (double &mulr, double &mulg, double &mulb) const { - temp2mul (temp, green, equal, mulr, mulg, mulb); + temp2mul (temp, green, equal, observer, mulr, mulg, mulb); } - void mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green) const; - static void temp2mulxyz (double tem, const std::string &method, double &Xxyz, double &Zxyz); + void mul2temp (const double rmul, const double gmul, const double bmul, const double equal, StandardObserver observer, double& temp, double& green) const; + static void temp2mulxyz (double tem, const std::string &method, StandardObserver observer, double &Xxyz, double &Zxyz); static void cieCAT02(double Xw, double Yw, double Zw, double &CAM02BB00, double &CAM02BB01, double &CAM02BB02, double &CAM02BB10, double &CAM02BB11, double &CAM02BB12, double &CAM02BB20, double &CAM02BB21, double &CAM02BB22, double adap ); static void cieCAT02float(float Xw, float Yw, float Zw, float &CAM02BB00, float &CAM02BB01, float &CAM02BB02, float &CAM02BB10, float &CAM02BB11, float &CAM02BB12, float &CAM02BB20, float &CAM02BB21, float &CAM02BB22, float adap); @@ -102,7 +118,7 @@ public: bool operator== (const ColorTemp& other) const { - return fabs(temp - other.temp) < 1e-10 && fabs(green - other.green) < 1e-10; + return fabs(temp - other.temp) < 1e-10 && fabs(green - other.green) < 1e-10 && observer != other.observer; } bool operator!= (const ColorTemp& other) const { @@ -375,13 +391,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 8eca727b4..7a2a5b4d5 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -5546,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) || @@ -7172,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 ------- @@ -8704,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, 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/dynamicprofile.cc b/rtengine/dynamicprofile.cc index 6dbd2d0f0..32be2ceb2 100644 --- a/rtengine/dynamicprofile.cc +++ b/rtengine/dynamicprofile.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -220,6 +221,22 @@ bool DynamicProfileRules::loadRules() try { rule.profilepath = kf.get_string (group, "profilepath"); + #if defined (WIN32) + // if this is Windows, replace any "/" in the path with "\\" + size_t pos = rule.profilepath.find("/"); + while (pos != Glib::ustring::npos) { + rule.profilepath.replace(pos, 1, "\\"); + pos = rule.profilepath.find("/", pos); + } + #endif + #if !defined (WIN32) + // if this is not Windows, replace any "\\" in the path with "/" + size_t pos = rule.profilepath.find("\\"); + while (pos != Glib::ustring::npos) { + rule.profilepath.replace(pos, 1, "/"); + pos = rule.profilepath.find("\\", pos); + } + #endif } catch (Glib::KeyFileError &) { dynamicRules.pop_back(); } @@ -254,7 +271,14 @@ bool DynamicProfileRules::storeRules() kf.set_string (group, "profilepath", rule.profilepath); } - return kf.save_to_file (Glib::build_filename (Options::rtdir, "dynamicprofile.cfg")); + std::string fn = Glib::build_filename (Options::rtdir, "dynamicprofile.cfg"); + if (Glib::file_test(fn, Glib::FILE_TEST_IS_SYMLINK)) { + // file is symlink; use target instead + // symlinks apparently are not recognízed on Windows + return kf.save_to_file (g_file_read_link (fn.c_str(), NULL)); + } else { + return kf.save_to_file (fn); + } } const std::vector &DynamicProfileRules::getRules() diff --git a/rtengine/filmnegativeproc.cc b/rtengine/filmnegativeproc.cc index ae1813db9..eb029d77a 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 = {}; @@ -340,7 +340,7 @@ bool rtengine::ImProcFunctions::filmNegativeProcess( imgsrc->getWBMults(currWB, params->raw, scale_mul, autoGainComp, rm, gm, bm); float rm2, gm2, bm2; - imgsrc->getWBMults(rtengine::ColorTemp(3500., 1., 1., "Custom"), params->raw, scale_mul, autoGainComp, rm2, gm2, bm2); + imgsrc->getWBMults(rtengine::ColorTemp(3500., 1., 1., "Custom", currWB.getObserver()), params->raw, scale_mul, autoGainComp, rm2, gm2, bm2); float mg = rtengine::max(rm2, gm2, bm2); rm2 /= mg; gm2 /= mg; @@ -611,7 +611,7 @@ void rtengine::Thumbnail::processFilmNegativeV2( // as in the main image processing. double r, g, b; - ColorTemp(3500., 1., 1., "Custom").getMultipliers(r, g, b); + ColorTemp(3500., 1., 1., "Custom", params.wb.observer).getMultipliers(r, g, b); //iColorMatrix is cam_rgb const double rm = camwbRed / (iColorMatrix[0][0] * r + iColorMatrix[0][1] * g + iColorMatrix[0][2] * b); const double gm = camwbGreen / (iColorMatrix[1][0] * r + iColorMatrix[1][1] * g + iColorMatrix[1][2] * b); 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/histmatching.cc b/rtengine/histmatching.cc index d3c5d0190..350dbbfab 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -229,7 +229,7 @@ void mappingToCurve(const std::vector &mapping, std::vector &curve) } // namespace -void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, std::vector &outCurve) +void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, StandardObserver observer, std::vector &outCurve) { BENCHFUN @@ -313,7 +313,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st eSensorType sensor_type; double scale; int w = fw / skip, h = fh / skip; - std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, false, true)); + std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, observer, false, true)); if (!thumb) { if (settings->verbose) { std::cout << "histogram matching: raw decoding failed, generating a neutral curve" << std::endl; 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/imagefloat.h b/rtengine/imagefloat.h index 3bee52d9a..38a4bf651 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 a8ea8f851..1f4c2179a 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,11 +117,11 @@ 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 getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) = 0; + virtual ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal, StandardObserver observer) = 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, const procparams::WBParams & wbpar) = 0; virtual double getDefGain () const { @@ -167,7 +167,7 @@ public: } // for RAW files, compute a tone curve using histogram matching on the embedded thumbnail - virtual void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, std::vector &outCurve) + virtual void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, StandardObserver observer, std::vector &outCurve) { outCurve = { 0.0 }; } @@ -195,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 b64485bbb..75b37222f 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), @@ -409,11 +410,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (imageTypeListener) { 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 { @@ -484,7 +489,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (todo & (M_INIT | M_LINDENOISE | M_HDR)) { if (params->wb.method == "autitcgreen") { - imgsrc->getrgbloc(0, 0, fh, fw, 0, 0, fh, fw); + imgsrc->getrgbloc(0, 0, fh, fw, 0, 0, fh, fw, params->wb); } } @@ -510,15 +515,14 @@ 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) { printf("Applying white balance, color correction & sRBG conversion...\n"); } - currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method); + currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method, params->wb.observer); float studgood = 1000.f; if (!params->wb.enabled) { @@ -527,7 +531,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) currWB = imgsrc->getWB(); lastAwbauto = ""; //reinitialize auto } else if (autowb) { - if (params->wb.method == "autitcgreen" || lastAwbEqual != params->wb.equal || lastAwbTempBias != params->wb.tempBias || lastAwbauto != params->wb.method) { + if (params->wb.method == "autitcgreen" || lastAwbEqual != params->wb.equal || lastAwbObserver != params->wb.observer || lastAwbTempBias != params->wb.tempBias || lastAwbauto != params->wb.method) { double rm, gm, bm; double tempitc = 5000.f; double greenitc = 1.; @@ -538,12 +542,14 @@ 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; params->wb.green = greenitc; - currWB = ColorTemp(params->wb.temperature, params->wb.green, 1., params->wb.method); + currWB = ColorTemp(params->wb.temperature, params->wb.green, 1., params->wb.method, params->wb.observer); + //printf("tempitc=%f greitc=%f\n", tempitc, greenitc); + currWB.getMultipliers(rm, gm, bm); } @@ -554,15 +560,17 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) bias = 0.; } - autoWB.update(rm, gm, bm, params->wb.equal, bias); + autoWB.update(rm, gm, bm, params->wb.equal, params->wb.observer, bias); lastAwbEqual = params->wb.equal; + lastAwbObserver = params->wb.observer; lastAwbTempBias = params->wb.tempBias; lastAwbauto = params->wb.method; } else { lastAwbEqual = -1.; + lastAwbObserver = ColorTemp::DEFAULT_OBSERVER; lastAwbTempBias = 0.0; lastAwbauto = ""; - autoWB.useDefaults(params->wb.equal); + autoWB.useDefaults(params->wb.equal, params->wb.observer); } @@ -570,17 +578,24 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) currWB = autoWB; } + double rw = 1.; + double gw = 1.; + double bw = 1.; if (params->wb.enabled) { - params->wb.temperature = currWB.getTemp(); + currWB = currWB.convertObserver(params->wb.observer); + params->wb.temperature = static_cast(currWB.getTemp()); params->wb.green = currWB.getGreen(); + currWB.getMultipliers(rw, gw, bw); + imgsrc->wbMul2Camera(rw, gw, bw); + // printf("ra=%f ga=%f ba=%f\n", rw, gw, bw); } - if (autowb && awbListener) { + if (awbListener) { if (params->wb.method == "autitcgreen") { - awbListener->WBChanged(params->wb.temperature, params->wb.green, studgood); - } else if (params->wb.method == "autold") { - awbListener->WBChanged(params->wb.temperature, params->wb.green, -1.f); + awbListener->WBChanged(params->wb.temperature, params->wb.green, rw, gw, bw, studgood); + } else { + awbListener->WBChanged(params->wb.temperature, params->wb.green, rw, gw, bw, -1.f); } } @@ -617,8 +632,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; @@ -778,7 +793,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (params->toneCurve.histmatching) { if (!params->toneCurve.fromHistMatching) { - imgsrc->getAutoMatchedToneCurve(params->icm, params->toneCurve.curve); + imgsrc->getAutoMatchedToneCurve(params->icm, params->wb.observer, params->toneCurve.curve); } if (params->toneCurve.autoexp) { @@ -2448,11 +2463,11 @@ bool ImProcCoordinator::updateWaveforms() return true; } -bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, double tempBias) +bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, StandardObserver observer, double tempBias) { if (imgsrc) { - if (lastAwbEqual != equal || lastAwbTempBias != tempBias || lastAwbauto != params->wb.method) { + if (lastAwbEqual != equal || lastAwbObserver != observer || lastAwbTempBias != tempBias || lastAwbauto != params->wb.method) { // Issue 2500 MyMutex::MyLock lock(minit); // Also used in crop window double rm, gm, bm; params->wb.method = "autold";//same result as before multiple Auto WB @@ -2462,16 +2477,18 @@ 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); + autoWB.update(rm, gm, bm, equal, observer, tempBias); lastAwbEqual = equal; + lastAwbObserver = observer; lastAwbTempBias = tempBias; lastAwbauto = params->wb.method; } else { lastAwbEqual = -1.; - autoWB.useDefaults(equal); + lastAwbObserver = ColorTemp::DEFAULT_OBSERVER; + autoWB.useDefaults(equal, observer); lastAwbauto = ""; lastAwbTempBias = 0.0; } @@ -2488,12 +2505,13 @@ bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, dou } } -void ImProcCoordinator::getCamWB(double& temp, double& green) +void ImProcCoordinator::getCamWB(double& temp, double& green, StandardObserver observer) { if (imgsrc) { - temp = imgsrc->getWB().getTemp(); - green = imgsrc->getWB().getGreen(); + const ColorTemp color_temp = imgsrc->getWB().convertObserver(observer); + temp = color_temp.getTemp(); + green = color_temp.getGreen(); } } @@ -2515,8 +2533,8 @@ void ImProcCoordinator::getSpotWB(int x, int y, int rect, double& temp, double& int tr = getCoarseBitMask(params->coarse); - ret = imgsrc->getSpotWB(red, green, blue, tr, params->wb.equal); - currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method); + ret = imgsrc->getSpotWB(red, green, blue, tr, params->wb.equal, params->wb.observer); + currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method, params->wb.observer); //double rr,gg,bb; //currWB.getMultipliers(rr,gg,bb); @@ -2622,23 +2640,25 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a imgsrc->preprocess(ppar.raw, ppar.lensProf, ppar.coarse); double dummy = 0.0; imgsrc->demosaic(ppar.raw, false, dummy); - ColorTemp currWB = ColorTemp(validParams->wb.temperature, validParams->wb.green, validParams->wb.equal, validParams->wb.method); + ColorTemp currWB = ColorTemp(validParams->wb.temperature, validParams->wb.green, validParams->wb.equal, validParams->wb.method, validParams->wb.observer); if (validParams->wb.method == "Camera") { currWB = imgsrc->getWB(); } else if (validParams->wb.method == "autold") { - if (lastAwbEqual != validParams->wb.equal || lastAwbTempBias != validParams->wb.tempBias) { + if (lastAwbEqual != validParams->wb.equal || lastAwbObserver != validParams->wb.observer || lastAwbTempBias != validParams->wb.tempBias) { double rm, gm, bm; imgsrc->getAutoWBMultipliers(rm, gm, bm); if (rm != -1.) { - autoWB.update(rm, gm, bm, validParams->wb.equal, validParams->wb.tempBias); + autoWB.update(rm, gm, bm, validParams->wb.equal, validParams->wb.observer, validParams->wb.tempBias); lastAwbEqual = validParams->wb.equal; + lastAwbObserver = validParams->wb.observer; lastAwbTempBias = validParams->wb.tempBias; } else { lastAwbEqual = -1.; + lastAwbObserver = ColorTemp::DEFAULT_OBSERVER; lastAwbTempBias = 0.0; - autoWB.useDefaults(validParams->wb.equal); + autoWB.useDefaults(validParams->wb.equal, validParams->wb.observer); } } @@ -2649,7 +2669,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/improccoordinator.h b/rtengine/improccoordinator.h index 85f28004a..92cdd91c7 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -80,6 +80,7 @@ protected: ColorTemp currWBitc; double lastAwbEqual; + StandardObserver lastAwbObserver{ColorTemp::DEFAULT_OBSERVER}; double lastAwbTempBias; Glib::ustring lastAwbauto; @@ -433,8 +434,8 @@ public: void setTweakOperator (TweakOperator *tOperator) override; void unsetTweakOperator (TweakOperator *tOperator) override; - bool getAutoWB (double& temp, double& green, double equal, double tempBias) override; - void getCamWB (double& temp, double& green) override; + bool getAutoWB (double& temp, double& green, double equal, StandardObserver observer, double tempBias) override; + void getCamWB (double& temp, double& green, StandardObserver observer) override; void getSpotWB (int x, int y, int rectSize, double& temp, double& green) override; bool getFilmNegativeSpot(int x, int y, int spotSize, FilmNegativeParams::RGB &refInput, FilmNegativeParams::RGB &refOutput) override; void getAutoCrop (double ratio, int &x, int &y, int &w, int &h) override; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 19a1907da..3f9a426cf 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -552,9 +552,9 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); - ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB - ColorTemp::temp2mulxyz(params->colorappearance.tempout, "Custom", Xwout, Zwout); - ColorTemp::temp2mulxyz(params->colorappearance.tempsc, "Custom", Xwsc, Zwsc); + ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, params->wb.observer, Xw, Zw); //compute white Xw Yw Zw : white current WB + ColorTemp::temp2mulxyz(params->colorappearance.tempout, "Custom", params->wb.observer, Xwout, Zwout); + ColorTemp::temp2mulxyz(params->colorappearance.tempsc, "Custom", params->wb.observer, Xwsc, Zwsc); //viewing condition for surrsrc if (params->colorappearance.surrsrc == "Average") { @@ -5645,7 +5645,7 @@ double ImProcFunctions::getAutoDistor(const Glib::ustring &fname, int thumb_size return 0.0; } - Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, ri, sensorType, w_raw, h_raw, 1, 1.0, FALSE); + Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, ri, sensorType, w_raw, h_raw, 1, 1.0, ColorTemp::DEFAULT_OBSERVER, FALSE); if (!raw) { delete thumb; diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index f7c3f2efc..599c9fd92 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -2130,7 +2130,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; @@ -2589,9 +2589,9 @@ void ImProcFunctions::ciecamloc_02float(const struct local_params& lp, int sp, L } } - ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB - ColorTemp::temp2mulxyz(tempo, "Custom", Xwout, Zwout); - ColorTemp::temp2mulxyz(5000, "Custom", Xwsc, Zwsc); + ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, params->wb.observer, Xw, Zw); //compute white Xw Yw Zw : white current WB + ColorTemp::temp2mulxyz(tempo, "Custom", params->wb.observer, Xwout, Zwout); + ColorTemp::temp2mulxyz(5000, "Custom", params->wb.observer, Xwsc, Zwsc); //viewing condition for surrsrc f = 1.00f; @@ -7945,7 +7945,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; } @@ -10671,7 +10671,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"); @@ -12805,7 +12805,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; @@ -13446,7 +13445,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; } @@ -14190,7 +14189,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}; 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..afaf0cbca 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -42,20 +42,20 @@ PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext if (ext.lowercase() == "jpg" || ext.lowercase() == "jpeg") { // int deg = infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); + tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., ColorTemp::DEFAULT_OBSERVER, true); if (tpp) { data = tpp->getImage8Data(); } } else if (ext.lowercase() == "png") { - tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); + tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., ColorTemp::DEFAULT_OBSERVER, true); if (tpp) { data = tpp->getImage8Data(); } } else if (ext.lowercase() == "tif" || ext.lowercase() == "tiff") { // int deg = infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); + tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., ColorTemp::DEFAULT_OBSERVER, true); if (tpp) { data = tpp->getImage8Data(); @@ -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/procparams.cc b/rtengine/procparams.cc index d8103540d..a421be9b3 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -27,6 +27,7 @@ #include #include "color.h" +#include "colortemp.h" #include "curves.h" #include "procparams.h" #include "utils.h" @@ -64,6 +65,40 @@ Glib::ustring expandRelativePath(const Glib::ustring &procparams_fname, const Gl return absPath; } +Glib::ustring expandRelativePath2(const Glib::ustring &procparams_fname, const Glib::ustring &procparams_fname2, const Glib::ustring &prefix, Glib::ustring embedded_fname) +{ + #if defined (WIN32) + // if this is Windows, replace any "/" in the filename with "\\" + size_t pos = embedded_fname.find("/"); + while (pos != string::npos) { + embedded_fname.replace(pos, 1, "\\"); + pos = embedded_fname.find("/", pos); + } + #endif + #if !defined (WIN32) + // if this is not Windows, replace any "\\" in the filename with "/" + size_t pos = embedded_fname.find("\\"); + while (pos != string::npos) { + embedded_fname.replace(pos, 1, "/"); + pos = embedded_fname.find("\\", pos); + } + #endif + + // if embedded_fname is not already an absolute path, + // try to convert it using procparams_fname (the directory of the raw file) as prefix + Glib::ustring rPath = expandRelativePath(procparams_fname, prefix, embedded_fname); + if (rPath.length() >= prefix.length() + && !Glib::file_test(rPath.substr(prefix.length()), Glib::FILE_TEST_IS_REGULAR) + && !procparams_fname2.empty() + && Glib::path_is_absolute(procparams_fname2)) { + // embedded_fname is not a valid path; + // try with procparams_fname2 (the path defined in Preferences) as a prefix + rPath = expandRelativePath(procparams_fname2 + G_DIR_SEPARATOR_S, prefix, embedded_fname); + } + return(rPath); +} + + Glib::ustring relativePathIfInside(const Glib::ustring &procparams_fname, bool fnameAbsolute, Glib::ustring embedded_fname) { if (fnameAbsolute || embedded_fname.empty() || !Glib::path_is_absolute(procparams_fname)) { @@ -92,6 +127,25 @@ Glib::ustring relativePathIfInside(const Glib::ustring &procparams_fname, bool f return prefix + embedded_fname.substr(dir1.length()); } +Glib::ustring relativePathIfInside2(const Glib::ustring &procparams_fname, const Glib::ustring &procparams_fname2, bool fnameAbsolute, Glib::ustring embedded_fname) +{ + // try to convert embedded_fname to a path relative to procparams_fname + // (the directory of the raw file) + // (note: fnameAbsolute seems to be always true, so this will never return a relative path) + Glib::ustring rPath = relativePathIfInside(procparams_fname, fnameAbsolute, embedded_fname); + if ((Glib::path_is_absolute(rPath) + || (rPath.length() >= 5 && rPath.substr(0, 5) == "file:" && Glib::path_is_absolute(rPath.substr(5)))) + && !procparams_fname2.empty() + && Glib::path_is_absolute(procparams_fname2)) { + // if path is not relative to the directory of the raw file, + // try to convert embedded_fname to a path relative to procparams_fname2 + // (the path defined in Preferences) + rPath = relativePathIfInside(procparams_fname2 + G_DIR_SEPARATOR_S, false, embedded_fname); + } + return(rPath); +} + + void getFromKeyfile( const Glib::KeyFile& keyfile, const Glib::ustring& group_name, @@ -373,7 +427,7 @@ ToneCurveParams::ToneCurveParams() : autoexp(false), clip(0.02), hrenabled(false), - method("Blend"), + method("Coloropp"), expcomp(0), curve{ DCT_Linear @@ -390,6 +444,7 @@ ToneCurveParams::ToneCurveParams() : shcompr(50), hlcompr(0), hlbl(0), + hlth(1.0), hlcomprthresh(0), histmatching(false), fromHistMatching(false), @@ -416,6 +471,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 +496,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 @@ -1328,7 +1385,19 @@ WBParams::WBParams() : temperature(6504), green(1.0), equal(1.0), - tempBias(0.0) + tempBias(0.0), + observer(ColorTemp::DEFAULT_OBSERVER), + itcwb_thres(34), + itcwb_precis(3), + itcwb_size(3), + itcwb_delta(2), + itcwb_fgreen(5), + itcwb_rgreen(1), + itcwb_nopurple(true), + itcwb_sorted(false), + itcwb_forceextra(false), + itcwb_sampling(false) + { } @@ -1348,6 +1417,7 @@ bool WBParams::isPanningRelatedChange(const WBParams& other) const && green == other.green && equal == other.equal && tempBias == other.tempBias + && observer == other.observer ) ) ); @@ -1361,7 +1431,19 @@ bool WBParams::operator ==(const WBParams& other) const && temperature == other.temperature && green == other.green && equal == other.equal - && tempBias == other.tempBias; + && tempBias == other.tempBias + && observer == other.observer + && itcwb_thres == other.itcwb_thres + && itcwb_precis == other.itcwb_precis + && itcwb_size == other.itcwb_size + && itcwb_delta == other.itcwb_delta + && itcwb_fgreen == other.itcwb_fgreen + && itcwb_rgreen == other.itcwb_rgreen + && itcwb_nopurple == other.itcwb_nopurple + && itcwb_sorted == other.itcwb_sorted + && itcwb_forceextra == other.itcwb_forceextra + && itcwb_sampling == other.itcwb_sampling; + } bool WBParams::operator !=(const WBParams& other) const @@ -5940,6 +6022,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"}, @@ -6132,6 +6215,17 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wb.green, "White Balance", "Green", wb.green, keyFile); saveToKeyfile(!pedited || pedited->wb.equal, "White Balance", "Equal", wb.equal, keyFile); saveToKeyfile(!pedited || pedited->wb.tempBias, "White Balance", "TemperatureBias", wb.tempBias, keyFile); + saveToKeyfile(!pedited || pedited->wb.observer, "White Balance", "StandardObserver", Glib::ustring(wb.observer == StandardObserver::TWO_DEGREES ? "TWO_DEGREES" : "TEN_DEGREES"), keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_thres, "White Balance", "Itcwb_thres", wb.itcwb_thres, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_precis, "White Balance", "Itcwb_precis", wb.itcwb_precis, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_size, "White Balance", "Itcwb_size", wb.itcwb_size, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_delta, "White Balance", "Itcwb_delta", wb.itcwb_delta, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_fgreen, "White Balance", "Itcwb_findgreen", wb.itcwb_fgreen, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_rgreen, "White Balance", "Itcwb_rangegreen", wb.itcwb_rgreen, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_nopurple, "White Balance", "Itcwb_nopurple", wb.itcwb_nopurple, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_sorted, "White Balance", "Itcwb_sorted", wb.itcwb_sorted, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_forceextra, "White Balance", "Itcwb_forceextra", wb.itcwb_forceextra, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_sampling, "White Balance", "Itcwb_sampling", wb.itcwb_sampling, keyFile); // Colorappearance saveToKeyfile(!pedited || pedited->colorappearance.enabled, "Color appearance", "Enabled", colorappearance.enabled, keyFile); @@ -6322,7 +6416,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo // Lens profile saveToKeyfile(!pedited || pedited->lensProf.lcMode, "LensProfile", "LcMode", lensProf.getMethodString(lensProf.lcMode), keyFile); - saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", relativePathIfInside(fname, fnameAbsolute, lensProf.lcpFile), keyFile); + saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", relativePathIfInside2(fname, options.rtSettings.lensProfilesPath, fnameAbsolute, lensProf.lcpFile), keyFile); saveToKeyfile(!pedited || pedited->lensProf.useDist, "LensProfile", "UseDistortion", lensProf.useDist, keyFile); saveToKeyfile(!pedited || pedited->lensProf.useVign, "LensProfile", "UseVignette", lensProf.useVign, keyFile); saveToKeyfile(!pedited || pedited->lensProf.useCA, "LensProfile", "UseCA", lensProf.useCA, keyFile); @@ -7143,7 +7237,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->prsharpening.deconviter, "PostResizeSharpening", "DeconvIterations", prsharpening.deconviter, keyFile); // Color management - saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.inputProfile), keyFile); + saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", relativePathIfInside2(fname, options.rtSettings.cameraProfilesPath, fnameAbsolute, icm.inputProfile), keyFile); saveToKeyfile(!pedited || pedited->icm.toneCurve, "Color Management", "ToneCurve", icm.toneCurve, keyFile); saveToKeyfile(!pedited || pedited->icm.applyLookTable, "Color Management", "ApplyLookTable", icm.applyLookTable, keyFile); saveToKeyfile(!pedited || pedited->icm.applyBaselineExposureOffset, "Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset, keyFile); @@ -7516,9 +7610,9 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->colorToning.labregionsShowMask, "ColorToning", "LabRegionsShowMask", colorToning.labregionsShowMask, keyFile); // Raw - saveToKeyfile(!pedited || pedited->raw.darkFrame, "RAW", "DarkFrame", relativePathIfInside(fname, fnameAbsolute, raw.dark_frame), keyFile); + saveToKeyfile(!pedited || pedited->raw.darkFrame, "RAW", "DarkFrame", relativePathIfInside2(fname, options.rtSettings.darkFramesPath, fnameAbsolute, raw.dark_frame), keyFile); 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_file, "RAW", "FlatFieldFile", relativePathIfInside2(fname, options.rtSettings.flatFieldsPath, 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); @@ -7734,6 +7828,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")) { @@ -8071,6 +8166,17 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Vibrance", "PastSatTog", pedited, vibrance.pastsattog, pedited->vibrance.pastsattog); assignFromKeyfile(keyFile, "Vibrance", "SkinTonesCurve", pedited, vibrance.skintonescurve, pedited->vibrance.skintonescurve); } + if (ppVersion <= 346) { // 5.8 and earlier. + wb.observer = StandardObserver::TWO_DEGREES; + if (pedited) { + pedited->wb.observer = true; + } + } else if (ppVersion <= 349) { // 5.9 + wb.observer = StandardObserver::TEN_DEGREES; + if (pedited) { + pedited->wb.observer = true; + } + } if (keyFile.has_group("White Balance")) { assignFromKeyfile(keyFile, "White Balance", "Enabled", pedited, wb.enabled, pedited->wb.enabled); assignFromKeyfile(keyFile, "White Balance", "Setting", pedited, wb.method, pedited->wb.method); @@ -8081,6 +8187,29 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "White Balance", "Green", pedited, wb.green, pedited->wb.green); assignFromKeyfile(keyFile, "White Balance", "Equal", pedited, wb.equal, pedited->wb.equal); assignFromKeyfile(keyFile, "White Balance", "TemperatureBias", pedited, wb.tempBias, pedited->wb.tempBias); + Glib::ustring standard_observer; + assignFromKeyfile(keyFile, "White Balance", "StandardObserver", pedited, standard_observer, pedited->wb.observer); + if (standard_observer == "TEN_DEGREES") { + wb.observer = StandardObserver::TEN_DEGREES; + } else if (standard_observer == "TWO_DEGREES") { + wb.observer = StandardObserver::TWO_DEGREES; + } + assignFromKeyfile(keyFile, "White Balance", "Itcwb_thres", pedited, wb.itcwb_thres, pedited->wb.itcwb_thres); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_precis", pedited, wb.itcwb_precis, pedited->wb.itcwb_precis); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_size", pedited, wb.itcwb_size, pedited->wb.itcwb_size); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_delta", pedited, wb.itcwb_delta, pedited->wb.itcwb_delta); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_findgreen", pedited, wb.itcwb_fgreen, pedited->wb.itcwb_fgreen); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_rangegreen", pedited, wb.itcwb_rgreen, pedited->wb.itcwb_rgreen); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_nopurple", pedited, wb.itcwb_nopurple, pedited->wb.itcwb_nopurple); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_sorted", pedited, wb.itcwb_sorted, pedited->wb.itcwb_sorted); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_forceextra", pedited, wb.itcwb_forceextra, pedited->wb.itcwb_forceextra); + if (ppVersion <= 349) { // 5.9 and earlier. + wb.itcwb_sampling = true; + if (pedited) { + pedited->wb.itcwb_sampling = true; + } + } + assignFromKeyfile(keyFile, "White Balance", "Itcwb_sampling", pedited, wb.itcwb_sampling, pedited->wb.itcwb_sampling); } if (keyFile.has_group("Defringing")) { @@ -8383,7 +8512,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } if (keyFile.has_key("LensProfile", "LCPFile")) { - lensProf.lcpFile = expandRelativePath(fname, "", keyFile.get_string("LensProfile", "LCPFile")); + lensProf.lcpFile = expandRelativePath2(fname, options.rtSettings.lensProfilesPath, "", keyFile.get_string("LensProfile", "LCPFile")); if (pedited) { pedited->lensProf.lcpFile = true; @@ -9422,13 +9551,12 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("Color Management")) { if (keyFile.has_key("Color Management", "InputProfile")) { - icm.inputProfile = expandRelativePath(fname, "file:", keyFile.get_string("Color Management", "InputProfile")); + icm.inputProfile = expandRelativePath2(fname, options.rtSettings.cameraProfilesPath, "file:", keyFile.get_string("Color Management", "InputProfile")); if (pedited) { pedited->icm.inputProfile = true; } - } - + } assignFromKeyfile(keyFile, "Color Management", "ToneCurve", pedited, icm.toneCurve, pedited->icm.toneCurve); assignFromKeyfile(keyFile, "Color Management", "ApplyLookTable", pedited, icm.applyLookTable, pedited->icm.applyLookTable); assignFromKeyfile(keyFile, "Color Management", "ApplyBaselineExposureOffset", pedited, icm.applyBaselineExposureOffset, pedited->icm.applyBaselineExposureOffset); @@ -10010,7 +10138,23 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("Film Simulation")) { assignFromKeyfile(keyFile, "Film Simulation", "Enabled", pedited, filmSimulation.enabled, pedited->filmSimulation.enabled); - assignFromKeyfile(keyFile, "Film Simulation", "ClutFilename", pedited, filmSimulation.clutFilename, pedited->filmSimulation.clutFilename); + assignFromKeyfile(keyFile, "Film Simulation", "ClutFilename", pedited, filmSimulation.clutFilename, pedited->filmSimulation.clutFilename); + #if defined (WIN32) + // if this is Windows, replace any "/" in the filename with "\\" + size_t pos = filmSimulation.clutFilename.find("/"); + while (pos != string::npos) { + filmSimulation.clutFilename.replace(pos, 1, "\\"); + pos = filmSimulation.clutFilename.find("/", pos); + } + #endif + #if !defined (WIN32) + // if this is not Windows, replace any "\\" in the filename with "/" + size_t pos = filmSimulation.clutFilename.find("\\"); + while (pos != string::npos) { + filmSimulation.clutFilename.replace(pos, 1, "/"); + pos = filmSimulation.clutFilename.find("\\", pos); + } + #endif if (keyFile.has_key("Film Simulation", "Strength")) { if (ppVersion < 321) { @@ -10185,23 +10329,20 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("RAW")) { if (keyFile.has_key("RAW", "DarkFrame")) { - raw.dark_frame = expandRelativePath(fname, "", keyFile.get_string("RAW", "DarkFrame")); + raw.dark_frame = expandRelativePath2(fname, options.rtSettings.darkFramesPath, "", keyFile.get_string("RAW", "DarkFrame")); if (pedited) { pedited->raw.darkFrame = true; } } - assignFromKeyfile(keyFile, "RAW", "DarkFrameAuto", pedited, raw.df_autoselect, pedited->raw.df_autoselect); - if (keyFile.has_key("RAW", "FlatFieldFile")) { - raw.ff_file = expandRelativePath(fname, "", keyFile.get_string("RAW", "FlatFieldFile")); + raw.ff_file = expandRelativePath2(fname, options.rtSettings.flatFieldsPath, "", keyFile.get_string("RAW", "FlatFieldFile")); if (pedited) { pedited->raw.ff_file = true; } } - 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); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 00ec378f0..6be2be54c 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -60,6 +60,8 @@ class LocLLmaskexpCurve; class LocCCmaskexpCurve; class LocHHmaskexpCurve; +enum class StandardObserver; + enum RenderingIntent : int { RI_PERCEPTUAL = INTENT_PERCEPTUAL, RI_RELATIVE = INTENT_RELATIVE_COLORIMETRIC, @@ -300,6 +302,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; @@ -634,11 +637,22 @@ struct WBEntry { struct WBParams { bool enabled; - Glib::ustring method; - int temperature; - double green; - double equal; - double tempBias; + Glib::ustring method; + int temperature; + double green; + double equal; + double tempBias; + StandardObserver observer; + int itcwb_thres; + int itcwb_precis; + int itcwb_size; + int itcwb_delta; + int itcwb_fgreen; + int itcwb_rgreen; + bool itcwb_nopurple; + bool itcwb_sorted; + bool itcwb_forceextra; + bool itcwb_sampling; WBParams(); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 550c59e9c..06aa701e8 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -468,6 +468,7 @@ RawImageSource::RawImageSource () { embProfile = nullptr; rgbSourceModified = false; + for (int i = 0; i < 4; ++i) { psRedBrightness[i] = psGreenBrightness[i] = psBlueBrightness[i] = 1.f; } @@ -639,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 { @@ -689,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 @@ -705,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; @@ -790,22 +843,51 @@ 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) @@ -1214,7 +1296,7 @@ int RawImageSource::load (const Glib::ustring &fname, bool firstFrameOnly) double cam_r = imatrices.rgb_cam[0][0] * camwb_red + imatrices.rgb_cam[0][1] * camwb_green + imatrices.rgb_cam[0][2] * camwb_blue; double cam_g = imatrices.rgb_cam[1][0] * camwb_red + imatrices.rgb_cam[1][1] * camwb_green + imatrices.rgb_cam[1][2] * camwb_blue; double cam_b = imatrices.rgb_cam[2][0] * camwb_red + imatrices.rgb_cam[2][1] * camwb_green + imatrices.rgb_cam[2][2] * camwb_blue; - camera_wb = ColorTemp (cam_r, cam_g, cam_b, 1.); // as shot WB + camera_wb = ColorTemp (cam_r, cam_g, cam_b, 1., ColorTemp::DEFAULT_OBSERVER); // as shot WB if (settings->verbose) { printf("Raw As Shot White balance: temp %f, tint %f\n", camera_wb.getTemp(), camera_wb.getGreen()); @@ -1301,7 +1383,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le const double ref_r = imatrices.rgb_cam[0][0] * refwb_red + imatrices.rgb_cam[0][1] * refwb_green + imatrices.rgb_cam[0][2] * refwb_blue; const double ref_g = imatrices.rgb_cam[1][0] * refwb_red + imatrices.rgb_cam[1][1] * refwb_green + imatrices.rgb_cam[1][2] * refwb_blue; const double ref_b = imatrices.rgb_cam[2][0] * refwb_red + imatrices.rgb_cam[2][1] * refwb_green + imatrices.rgb_cam[2][2] * refwb_blue; - const ColorTemp ReferenceWB = ColorTemp (ref_r, ref_g, ref_b, 1.); + const ColorTemp ReferenceWB = ColorTemp (ref_r, ref_g, ref_b, 1., ColorTemp::DEFAULT_OBSERVER); if (settings->verbose) { printf("Raw Reference white balance: temp %f, tint %f, multipliers [%f %f %f | %f %f %f]\n", ReferenceWB.getTemp(), ReferenceWB.getGreen(), ref_r, ref_g, ref_b, refwb_red, refwb_blue, refwb_green); @@ -1697,7 +1779,6 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c rgbSourceModified = false; - if (cache) { if (!redCache) { redCache = new array2D(W, H); @@ -2396,7 +2477,6 @@ void RawImageSource::retinex(const ColorManagementParams& cmp, const RetinexPara } rgbSourceModified = false; // tricky handling for Color propagation - t5.set(); if (settings->verbose) { @@ -2442,16 +2522,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; + // } +// } } @@ -3460,6 +3541,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 @@ -3684,6 +3766,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); @@ -3954,7 +4037,7 @@ 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_low(int bfhitc, int bfwitc, const array2D & xc, const array2D & yc, const array2D & Yc, LUTf &xxx, LUTf &yyy, LUTf &YYY, LUTu &histxy) { //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 @@ -4419,6 +4502,570 @@ static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const ar } } + + + +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 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 + { + LUTu histxythr(histxy.getSize()); + histxythr.clear(); + LUTf xxxthr(xxx.getSize()); + xxxthr.clear(); + LUTf yyythr(yyy.getSize()); + 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 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.25f) { + nh = 1; + } 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 = 6; + } else if (yc[y][x] < 0.55f) { + nh = 7; + } else if (yc[y][x] < 0.6f) { + nh = 8; + } else if (yc[y][x] < 0.7f) { + nh = 9; + } else if (yc[y][x] < 0.82f) { + //green + nh = 10; + } + } else if (xc[y][x] < 0.24f && yc[y][x] > 0.05f) { + if (yc[y][x] < 0.2f) { + nh = 11; + } else if (yc[y][x] < 0.25f) { + nh = 12; + } else if (yc[y][x] < 0.3f) { + nh = 13; + } else if (yc[y][x] < 0.35f) { + nh = 14; + } else if (yc[y][x] < 0.4f) { + nh = 15; + } else if (yc[y][x] < 0.45f) { + nh = 16; + } else if (yc[y][x] < 0.5f) { + 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.28f && yc[y][x] > 0.1f) {//blue sky and other + if (yc[y][x] < 0.2f) { + nh = 22; + } else if (yc[y][x] < 0.23f) { + nh = 23; + } else if (yc[y][x] < 0.25f) { + nh = 24; + } else if (yc[y][x] < 0.27f) { + nh = 25; + } else if (yc[y][x] < 0.29f) { + nh = 26; + } else if (yc[y][x] < 0.31f) { + nh = 27; + } else if (yc[y][x] < 0.33f) { + nh = 28; + } 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 = 50; + } else if (yc[y][x] < 0.22f) { + nh = 51; + } else if (yc[y][x] < 0.24f) { + nh = 52; + } else if (yc[y][x] < 0.29f) { + nh = 53; + } else if (yc[y][x] < 0.32f) { + nh = 54; + } else if (yc[y][x] < 0.33f) { + nh = 55; + } else if (yc[y][x] < 0.335f) { + nh = 56; + } else if (yc[y][x] < 0.34f) { + nh = 57; + } else if (yc[y][x] < 0.35f) { + nh = 58; + } else if (yc[y][x] < 0.37f) { + nh = 59; + } else if (yc[y][x] < 0.4f) { + nh = 60; + } else if (yc[y][x] < 0.45f) { + nh = 61; + } else if (yc[y][x] < 0.5f) { + nh = 62; + } else if (yc[y][x] < 0.55f) { + 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 = 66; + } + } else if (xc[y][x] < 0.335f && yc[y][x] > 0.1f) {//neutral + if (yc[y][x] < 0.2f) { + nh = 67; + } else if (yc[y][x] < 0.22f) { + nh = 68; + } else if (yc[y][x] < 0.24f) { + nh = 69; + } else if (yc[y][x] < 0.27f) { + nh = 70; + } else if (yc[y][x] < 0.29f) { + nh = 71; + } else if (yc[y][x] < 0.32f) { + nh = 72; + } else if (yc[y][x] < 0.33f) { + nh = 73; + } else if (yc[y][x] < 0.335f) { + nh = 74; + } else if (yc[y][x] < 0.34f) { + nh = 75; + } else if (yc[y][x] < 0.345f) { + nh = 76; + } else if (yc[y][x] < 0.35f) { + nh = 77; + } else if (yc[y][x] < 0.355f) { + nh = 78; + } else if (yc[y][x] < 0.36f) { + nh = 79; + } else if (yc[y][x] < 0.37f) { + nh = 80; + } else if (yc[y][x] < 0.38f) { + nh = 81; + } else if (yc[y][x] < 0.4f) { + nh = 82; + } else if (yc[y][x] < 0.45f) { + nh = 83; + } else if (yc[y][x] < 0.5f) { + nh = 84; + } else if (yc[y][x] < 0.55f) { + 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 = 88; + } + } else if (xc[y][x] < 0.340f && yc[y][x] > 0.1f) {//neutral + if (yc[y][x] < 0.2f) { + nh = 89; + } else if (yc[y][x] < 0.22f) { + nh = 90; + } else if (yc[y][x] < 0.24f) { + nh = 91; + } else if (yc[y][x] < 0.29f) { + nh = 92; + } else if (yc[y][x] < 0.32f) { + nh = 93; + } else if (yc[y][x] < 0.325f) { + nh = 94; + } else if (yc[y][x] < 0.33f) { + nh = 95; + } else if (yc[y][x] < 0.335f) { + nh = 96; + } else if (yc[y][x] < 0.34f) { + nh = 97; + } else if (yc[y][x] < 0.345f) { + nh = 98; + } else if (yc[y][x] < 0.35f) { + nh = 99; + } else if (yc[y][x] < 0.355f) { + nh = 100; + } else if (yc[y][x] < 0.36f) { + nh = 101; + } else if (yc[y][x] < 0.37f) { + nh = 102; + } else if (yc[y][x] < 0.38f) { + nh = 103; + } else if (yc[y][x] < 0.4f) { + nh = 104; + } else if (yc[y][x] < 0.45f) { + nh = 105; + } else if (yc[y][x] < 0.5f) { + nh = 106; + } else if (yc[y][x] < 0.55f) { + 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 = 110; + } + } else if (xc[y][x] < 0.345f && yc[y][x] > 0.1f) {//neutral 37 + if (yc[y][x] < 0.2f) { + nh = 111; + } else if (yc[y][x] < 0.22f) { + nh = 112; + } else if (yc[y][x] < 0.24f) { + nh = 113; + } else if (yc[y][x] < 0.26f) { + nh = 114; + } else if (yc[y][x] < 0.29f) { + nh = 115; + } else if (yc[y][x] < 0.32f) { + nh = 116; + } else if (yc[y][x] < 0.33f) { + nh = 117; + } else if (yc[y][x] < 0.335f) { + nh = 118; + } else if (yc[y][x] < 0.34f) { + nh = 119; + } else if (yc[y][x] < 0.345f) { + nh = 120; + } else if (yc[y][x] < 0.35f) { + nh = 121; + } else if (yc[y][x] < 0.355f) { + nh = 122; + } else if (yc[y][x] < 0.36f) { + nh = 123; + } else if (yc[y][x] < 0.37f) { + nh = 124; + } else if (yc[y][x] < 0.38f) { + nh = 125; + } else if (yc[y][x] < 0.39f) { + nh = 126; + } else if (yc[y][x] < 0.4f) { + nh = 127; + } else if (yc[y][x] < 0.42f) { + nh = 128; + } else if (yc[y][x] < 0.45f) { + nh = 129; + } else if (yc[y][x] < 0.48f) { + nh = 130; + } else if (yc[y][x] < 0.5f) { + nh = 131; + } else if (yc[y][x] < 0.55f) { + nh = 132; + } else if (yc[y][x] < 0.65f) { + nh = 133; + } + } else if (xc[y][x] < 0.355f && yc[y][x] > 0.1f) {//neutral 37 + if (yc[y][x] < 0.2f) { + nh = 134; + } else if (yc[y][x] < 0.22f) { + nh = 135; + } else if (yc[y][x] < 0.24f) { + nh = 136; + } else if (yc[y][x] < 0.26f) { + nh = 137; + } else if (yc[y][x] < 0.29f) { + nh = 138; + } else if (yc[y][x] < 0.32f) { + nh = 139; + } else if (yc[y][x] < 0.33f) { + nh = 140; + } else if (yc[y][x] < 0.335f) { + nh = 141; + } else if (yc[y][x] < 0.34f) { + nh = 142; + } else if (yc[y][x] < 0.345f) { + nh = 143; + } else if (yc[y][x] < 0.35f) { + nh = 144; + } else if (yc[y][x] < 0.355f) { + nh = 145; + } else if (yc[y][x] < 0.36f) { + nh = 146; + } else if (yc[y][x] < 0.37f) { + nh = 147; + } else if (yc[y][x] < 0.38f) { + nh = 148; + } else if (yc[y][x] < 0.39f) { + nh = 149; + } else if (yc[y][x] < 0.4f) { + nh = 150; + } else if (yc[y][x] < 0.42f) { + nh = 151; + } else if (yc[y][x] < 0.45f) { + nh = 152; + } else if (yc[y][x] < 0.48f) { + nh = 153; + } else if (yc[y][x] < 0.5f) { + nh = 154; + } else if (yc[y][x] < 0.55f) { + nh = 155; + } else if (yc[y][x] < 0.6f) { + nh = 156; + } else if (yc[y][x] < 0.65f) { + nh = 157; + } + } else if (xc[y][x] < 0.365f && yc[y][x] > 0.15f) { //0.4 + if (yc[y][x] < 0.2f) { + nh = 158; + } else if (yc[y][x] < 0.22f) { + nh = 159; + } else if (yc[y][x] < 0.24f) { + nh = 160; + } else if (yc[y][x] < 0.26f) { + nh = 161; + } else if (yc[y][x] < 0.29f) { + nh = 162; + } else if (yc[y][x] < 0.32f) { + nh = 163; + } else if (yc[y][x] < 0.33f) { + nh = 164; + } else if (yc[y][x] < 0.34f) { + nh = 165; + } else if (yc[y][x] < 0.35f) { + nh = 166; + } else if (yc[y][x] < 0.36f) { + nh = 167; + } else if (yc[y][x] < 0.37f) { + nh = 168; + } else if (yc[y][x] < 0.38f) { + nh = 169; + } else if (yc[y][x] < 0.39f) { + nh = 170; + } else if (yc[y][x] < 0.4f) { + nh = 171; + } else if (yc[y][x] < 0.42f) { + nh = 172; + } else if (yc[y][x] < 0.45f) { + nh = 173; + } else if (yc[y][x] < 0.5f) { + nh = 174; + } else if (yc[y][x] < 0.55f) { + nh = 175; + } else if (yc[y][x] < 0.63f) { + nh = 176; + } + } else if (xc[y][x] < 0.405f && yc[y][x] > 0.15f) {//45 + if (yc[y][x] < 0.2f && purp) {//no take into account if purp = false + nh = 177; + } else if (yc[y][x] < 0.22f && purp) { + nh = 178; + } else if (yc[y][x] < 0.24f && purp) { + nh = 179; + } else if (yc[y][x] < 0.26f && purp) { + nh = 180; + } else if (yc[y][x] < 0.29f && purp) { + nh = 181; + } else if (yc[y][x] < 0.32f) { + nh = 182; + } else if (yc[y][x] < 0.34f) { + nh = 183; + } 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 = 232; + } else if (yc[y][x] < 0.3f) { + nh = 233; + } else if (yc[y][x] < 0.35f) { + nh = 234; + } else if (yc[y][x] < 0.45f) { + nh = 235; + } + } else if (xc[y][x] < 0.75f && yc[y][x] > 0.1f) { + nh = 236; //191 + } + + if (nh >= 0) { + histxythr[nh]++; + xxxthr[nh] += xc[y][x]; + yyythr[nh] += yc[y][x]; + YYYthr[nh] += Yc[y][x]; + } + } + } + +#ifdef _OPENMP + #pragma omp critical +#endif + { + histxy += histxythr; + xxx += xxxthr; + yyy += yyythr; + YYY += YYYthr; + } + } +} + float static studentXY(const array2D & YYcurr, const array2D & reffYY, int sizcurr, int Nc, int tt) { //calculate Student coeff YY @@ -4431,24 +5078,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; @@ -4465,19 +5116,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 2 - 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 :) @@ -4507,7 +5161,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double 22) we re-adjust references color for these xyY from 20) 23) then find all Student correlation for each couple green / temp 24) sort these Student values, and choose the minimum - 25) then for the 3 better couple "temp / green" choose the one where green is nearest from 1. + 25) then for the 5 better couple "temp / green" choose the one where green is nearest from 1. Some variables or function are not used, keep in case of I have test with cat02 but result are not stable enough ! why ??, therefore cat02 neutralized @@ -4518,27 +5172,37 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double You can used it in images :flowers, landscape, portrait, skin, where illuminants are "normal" (daylight, blackbody) You must avoid when illuminant is non standard (fluorescent, LED...) and also, when the subject is lost in the image (some target to generate profiles). - You can change parameters in option.cc + You can change parameters in White Balance - Frame adapted to Itcwb 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_sizereference : 3 by default, can be set to 5 ==> size of reference color compare to size of histogram real color + Itcwb_greendelta : 1 - delta temp in green iterate loop for "extra" - between 0 to 4 + Itcwb_forceextra : false by default - Use all Ciexy diagram instead of sRGB + //Itcwb_sizereference : repalce by int maxnb 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 : replace by int precision = 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... + itcwb_fgreen : 5 by default - between 3 to 6 - find the compromise student / green to reach green near of 1 + + In file options. + use standard observer 10°, false = standard observer 2° */ -// BENCHFUN - - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix("sRGB"); + // BENCHFUN + + Glib::ustring profuse; + profuse = "sRGB";//or "Adobe RGB" + if( wbpar.itcwb_forceextra && wbpar.itcwb_sampling == false) {//Adobe RGB + profuse = "ACESp0";//cover all CIE xy diagram + } + + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(profuse); //ACESp0 or sRGB const float wp[3][3] = { {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, {static_cast(wprof[1][0]), static_cast(wprof[1][1]), static_cast(wprof[1][2])}, {static_cast(wprof[2][0]), static_cast(wprof[2][1]), static_cast(wprof[2][2])} }; - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix("sRGB"); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(profuse);//ACESp0 or sRGB //inverse matrix user select const float wip[3][3] = { {static_cast(wiprof[0][0]), static_cast(wiprof[0][1]), static_cast(wiprof[0][2])}, @@ -4570,7 +5234,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}, @@ -4579,7 +5243,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 2 range {0.727, 1.f}, {0.741, 1.f}, {0.755, 1.f}, @@ -4588,7 +5252,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {0.800, 1.f}, {0.806, 1.f}, {0.813, 1.f}, - {0.820, 1.f}, + {0.820, 1.f},//usual range {0.826, 1.f}, {0.833, 1.f}, {0.840, 1.f}, @@ -4610,7 +5274,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}, @@ -4635,20 +5299,20 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {1.220, 1.f}, {1.230, 1.f}, {1.240, 1.f}, - {1.250, 1.f}, + {1.250, 1.f},// usual range {1.275, 1.f}, {1.300, 1.f}, {1.325, 1.f}, {1.350, 1.f}, {1.375, 1.f}, - {1.400, 1.f}, + {1.400, 1.f},//usual 2 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}, @@ -4697,20 +5361,25 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double int end; } RangeGreen; - constexpr RangeGreen Rangestandard = {24, 86}; + constexpr RangeGreen Rangestandard = {33, 80};//usual green range + constexpr RangeGreen Rangestandard2 = {24, 86};//usual 2 green range constexpr RangeGreen Rangeextended = {15, 93}; const RangeGreen Rangemax = {0, N_g}; RangeGreen Rangegreenused; - if (settings->itcwb_greenrange == 0) { + if (wbpar.itcwb_rgreen == 0) { Rangegreenused = Rangestandard; - } else if (settings->itcwb_greenrange == 1) { + } else if (wbpar.itcwb_rgreen == 1) { + Rangegreenused = Rangestandard2; + } else if (wbpar.itcwb_rgreen == 2) { Rangegreenused = Rangeextended; } else { Rangegreenused = Rangemax; } - + if(wbpar.itcwb_sampling == true) { + Rangegreenused = Rangestandard2; + } typedef struct WbTxyz { double Tem; double XX; @@ -4778,7 +5447,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}, @@ -4857,10 +5526,12 @@ 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 - - //tempref and greenref are camera wb values. - // I used them by default to select good spectral values !! + int siza = 237; //192 untill 01/2023 size of histogram + if(wbpar.itcwb_sampling == true) { + siza = 192;//old sampling 5.9 and before... + } + // 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; @@ -4874,12 +5545,13 @@ 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; - ColorTemp WBiter = ColorTemp(Txyz[tt].Tem, greenitc, 1.f, "Custom"); + ColorTemp WBiter = ColorTemp(Txyz[tt].Tem, greenitc, 1.f, "Custom", wbpar.observer); WBiter.getMultipliers(r, g, b); + rm = imatrices.cam_rgb[0][0] * r + imatrices.cam_rgb[0][1] * g + imatrices.cam_rgb[0][2] * b; gm = imatrices.cam_rgb[1][0] * r + imatrices.cam_rgb[1][1] * g + imatrices.cam_rgb[1][2] * b; bm = imatrices.cam_rgb[2][0] * r + imatrices.cam_rgb[2][1] * g + imatrices.cam_rgb[2][2] * b; @@ -4924,19 +5596,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 @@ -4955,7 +5635,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double array2D yc(bfwitc, bfhitc); array2D Yc(bfwitc, bfhitc); - const int deltarepref = settings->itcwb_delta; + const int deltarepref = 1; //settings->itcwb_delta; for (int nn = 0, drep = -deltarepref; nn <= 2; ++nn, drep += deltarepref) { //three loop to refine color if temp camera is probably not very good @@ -4965,14 +5645,16 @@ 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]; const float GG = gmm[rep] * greenloc[y][x]; const float BB = bmm[rep] * blueloc[y][x]; - Color::rgbxyY(RR, GG, BB, xc[y][x], yc[y][x], Yc[y][x], wp); + Color::rgbxyY(RR, GG, BB, xc[y][x], yc[y][x], Yc[y][x], wp);//use sRGB or ACESp0 } } + //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 @@ -4982,8 +5664,20 @@ 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...) + if (hrp.hrenabled && hrp.method == "Coloropp" && wbpar.itcwb_nopurple == true) {//we disabled (user) with settings if image are naturally with purple (flowers...) + purp = false; + } + if(wbpar.itcwb_sampling == false) { + //printf("Use high smapling\n"); + 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) + } else { + //printf("Use low smapling - 5.9\n"); + histoxyY_low(bfhitc, bfwitc, xc, yc, Yc, xxx, yyy, YYY, histxy);//low scaling + } } // free some memory @@ -5014,15 +5708,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 } @@ -5047,7 +5745,15 @@ 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); + int nbm = 77;//number max of color used = 1.4 * 55 in case all CIExy diagram + if(profuse == "sRGB" || wbpar.itcwb_sampling == true) { + nbm = 55; + } + const int sizcu4 = rtengine::min(sizcu30, nbm);//size of chroma values + + 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; @@ -5062,6 +5768,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)); @@ -5075,14 +5782,25 @@ 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 + bool issorted = wbpar.itcwb_sorted; + + if(wbpar.itcwb_sampling == true) { + issorted = false; + } + + + if (issorted) { //sort in ascending with chroma values std::sort(wbchro, wbchro + sizcu4, wbchro[0]); } - const int maxval = rtengine::LIM(settings->itcwb_thres, 10, 55);//max values of color to find correlation + int maxval = rtengine::LIM(wbpar.itcwb_thres, 10, 55);//max values of color to find correlation + if(wbpar.itcwb_sampling == true) { + maxval = 34; + } sizcurr2ref = rtengine::min(sizcurr2ref, maxval); //keep about the biggest values, @@ -5097,15 +5815,18 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } //calculate deltaE xx to find best values of spectrals data - limited to chroma values - int maxnb = rtengine::LIM(settings->itcwb_sizereference, 1, 5); + // int maxnb = rtengine::LIM(settings->itcwb_sizereference, 1, 5); + // int maxnb = rtengine::LIM(wbpar.itcwb_size, 1, 5); + int maxnb = 3; + //wbpar.itcwb_size to verify if this setting is usefull...diificulties with High gamut and limited patch spectral colors. - if (settings->itcwb_thres > 55) { - maxnb = 201 / settings->itcwb_thres; + if (wbpar.itcwb_thres > 55) {//normally never used + maxnb = 201 / wbpar.itcwb_thres; } 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++) { @@ -5192,7 +5913,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; @@ -5206,21 +5927,24 @@ 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); + int dgoodref = rtengine::LIM(wbpar.itcwb_delta,1, 4); + if(wbpar.itcwb_sampling == true) { + dgoodref = 2; + } 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; for (int tt = scantempbeg; tt < scantempend; ++tt) { double r, g, b; - ColorTemp WBiter(Txyz[tt].Tem, gree[gr].green, 1.f, "Custom"); + ColorTemp WBiter(Txyz[tt].Tem, gree[gr].green, 1.f, "Custom", wbpar.observer); WBiter.getMultipliers(r, g, b); float rm = imatrices.cam_rgb[0][0] * r + imatrices.cam_rgb[0][1] * g + imatrices.cam_rgb[0][2] * b; float gm = imatrices.cam_rgb[1][0] * r + imatrices.cam_rgb[1][1] * g + imatrices.cam_rgb[1][2] * b; @@ -5249,6 +5973,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) { @@ -5257,6 +5982,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++; @@ -5264,6 +5990,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)); @@ -5272,6 +5999,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; @@ -5282,48 +6010,40 @@ 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; - - if (std::fabs(greengood2) < std::fabs(greengood1)) { - greengoodprov = greengood2; - goodrefprov = goodref2; - studprov = stud2; - } else { - greengoodprov = greengood1; - goodrefprov = goodref1; - studprov = stud1; + // 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; + int maxkgood = wbpar.itcwb_fgreen;//we can change ...to test 3, 4, 5. High values perhaps less good student, but it is a compromise... + maxkgood = rtengine::LIM(maxkgood, 3, 6); + if(wbpar.itcwb_sampling == true) { + maxkgood = 3; // force to 3 with old low sampling } - if (std::fabs(greengoodprov) < std::fabs(greengood0)) { - goodref = goodrefprov; - greengood = greengoodprov + 55; - studgood = studprov; + int mingood = std::min(std::fabs(Tgstud[0].greenref - 55), std::fabs(Tgstud[1].greenref - 55)); - } else { - goodref = goodref0; - greengood = greengood0 + 55; - studgood = stud0; + for (int k = 2; k < maxkgood; ++k) { + mingood = std::min(std::fabs(mingood), std::fabs(Tgstud[k].greenref - 55)); + } + + 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;; + } + } + + 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; @@ -5337,49 +6057,43 @@ 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 //put green (tint) in reasonable limits for an Daylight illuminant // avoid too bi or too low values if (wbpar.method == "autitcgreen") { - bool extra = false; + bool extra = true; if (greenref > 0.5 && greenref < 1.3) {// 0.5 and 1.3 arbitraties values greenitc = greenref; - if (settings->itcwb_forceextra) { - extra = true; - } } else { greenitc = 1.; extra = true; } 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); } } -void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) +void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, const WBParams & wbpar) { // BENCHFUN //used by auto WB local to calculate red, green, blue in local region - int precision = 5; - if (settings->itcwb_precis == 5) { + + int precision = 3;//must be 3 5 or 9 + if(wbpar.itcwb_sampling == true) { precision = 5; - } else if (settings->itcwb_precis < 5) { - 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 ; @@ -5404,6 +6118,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]; @@ -5411,6 +6126,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int nn++; } } + avgL /= nn; double vari = 0.f; @@ -5419,6 +6135,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]; @@ -5432,8 +6149,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; @@ -5444,7 +6163,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; @@ -5459,6 +6178,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++) { @@ -5468,7 +6188,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])); @@ -5507,18 +6227,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) { @@ -5532,7 +6252,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref } #ifdef _OPENMP - #pragma omp critical + #pragma omp critical #endif { avg_r += avg_c[0]; @@ -5549,9 +6269,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])); @@ -5569,7 +6289,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 @@ -5592,12 +6312,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]; @@ -5635,18 +6355,14 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref if (wbpar.method == "autitcgreen") { bool twotimes = false; - int precision = 5; - if (settings->itcwb_precis == 5) { + int precision = 3;//must be 3 5 or 9 + if(wbpar.itcwb_sampling == true) { precision = 5; - } else if (settings->itcwb_precis < 5) { - 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); @@ -5654,7 +6370,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") { @@ -5673,7 +6389,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; @@ -5710,7 +6426,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])); @@ -5793,7 +6509,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])); @@ -5875,7 +6591,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); @@ -5889,7 +6605,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) blueAWBMul = bm = imatrices.rgb_cam[2][0] * reds + imatrices.rgb_cam[2][1] * greens + imatrices.rgb_cam[2][2] * blues; } -ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) +ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal, StandardObserver observer) { int x; @@ -6097,7 +6813,7 @@ ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vector &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); @@ -141,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 getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) 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, const procparams::WBParams & wbpar) 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 @@ -154,7 +154,7 @@ public: return camera_wb; } 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; + ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal, StandardObserver observer) override; bool isWBProviderReady () override { return rawData; @@ -186,7 +186,7 @@ public: } void getAutoExpHistogram (LUTu & histogram, int& histcompr) override; void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) override; - void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, std::vector &outCurve) override; + void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, StandardObserver observer, std::vector &outCurve) override; DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) override; void convertColorSpace(Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) override; @@ -199,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 (); @@ -308,6 +309,9 @@ protected: 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 3916adfbe..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, diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 989ca3354..f86950457 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -472,7 +472,7 @@ class AutoWBListener { public: virtual ~AutoWBListener() = default; - virtual void WBChanged(double temp, double green, float studgood) = 0; + virtual void WBChanged(double temp, double green, double rw, double gw, double bw, float studgood) = 0; }; class FrameCountListener @@ -619,8 +619,8 @@ public: * @return a pointer to the Crop object that handles the image data trough its own pipeline */ virtual DetailedCrop* createCrop (::EditDataProvider *editDataProvider, bool isDetailWindow) = 0; - virtual bool getAutoWB (double& temp, double& green, double equal, double tempBias) = 0; - virtual void getCamWB (double& temp, double& green) = 0; + virtual bool getAutoWB (double& temp, double& green, double equal, StandardObserver observer, double tempBias) = 0; + virtual void getCamWB (double& temp, double& green, StandardObserver observer) = 0; virtual void getSpotWB (int x, int y, int rectSize, double& temp, double& green) = 0; virtual bool getFilmNegativeSpot(int x, int y, int spotSize, procparams::FilmNegativeParams::RGB &refInput, procparams::FilmNegativeParams::RGB &refOutput) = 0; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 86f1c1372..11dae8018 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -194,7 +194,7 @@ namespace rtengine using namespace procparams; -Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode) +Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool inspectorMode) { StdImageSource imgSrc; @@ -310,8 +310,9 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, tpp->blueAWBMul = avg_b / double (n); tpp->wbEqual = wbEq; tpp->wbTempBias = 0.0; + tpp->wbObserver = wbObserver; - cTemp.mul2temp (tpp->redAWBMul, tpp->greenAWBMul, tpp->blueAWBMul, tpp->wbEqual, tpp->autoWBTemp, tpp->autoWBGreen); + cTemp.mul2temp (tpp->redAWBMul, tpp->greenAWBMul, tpp->blueAWBMul, tpp->wbEqual, tpp->wbObserver, tpp->autoWBTemp, tpp->autoWBGreen); } tpp->init (); @@ -349,7 +350,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); @@ -543,7 +544,7 @@ RawMetaDataLocation Thumbnail::loadMetaDataFromRaw (const Glib::ustring& fname) return rml; } -Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching) +Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, bool forHistogramMatching) { RawImage *ri = new RawImage (fname); unsigned int tempImageNum = 0; @@ -982,9 +983,10 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati tpp->blueAWBMul = ri->get_rgb_cam (2, 0) * reds + ri->get_rgb_cam (2, 1) * greens + ri->get_rgb_cam (2, 2) * blues; tpp->wbEqual = wbEq; tpp->wbTempBias = 0.0; + tpp->wbObserver = wbObserver; ColorTemp cTemp; - cTemp.mul2temp (tpp->redAWBMul, tpp->greenAWBMul, tpp->blueAWBMul, tpp->wbEqual, tpp->autoWBTemp, tpp->autoWBGreen); + cTemp.mul2temp (tpp->redAWBMul, tpp->greenAWBMul, tpp->blueAWBMul, tpp->wbEqual, tpp->wbObserver, tpp->autoWBTemp, tpp->autoWBGreen); } if (rotate && ri->get_rotateDegree() > 0) { @@ -1121,18 +1123,19 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT float iso = metadata->getISOSpeed(imgNum); float fcomp = metadata->getExpComp(imgNum); - // check if the WB's equalizer value has changed - if (wbEqual < (params.wb.equal - 5e-4) || wbEqual > (params.wb.equal + 5e-4) || wbTempBias < (params.wb.tempBias - 5e-4) || wbTempBias > (params.wb.tempBias + 5e-4)) { + // check if the WB's equalizer, temperature bias, or observer value has changed + if (wbEqual < (params.wb.equal - 5e-4) || wbEqual > (params.wb.equal + 5e-4) || wbTempBias < (params.wb.tempBias - 5e-4) || wbTempBias > (params.wb.tempBias + 5e-4) || wbObserver != params.wb.observer) { wbEqual = params.wb.equal; wbTempBias = params.wb.tempBias; + wbObserver = params.wb.observer; // recompute the autoWB ColorTemp cTemp; - cTemp.mul2temp (redAWBMul, greenAWBMul, blueAWBMul, wbEqual, autoWBTemp, autoWBGreen); + cTemp.mul2temp (redAWBMul, greenAWBMul, blueAWBMul, wbEqual, wbObserver, autoWBTemp, autoWBGreen); autoWBTemp += autoWBTemp * wbTempBias; } // compute WB multipliers - ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); + ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method, params.wb.observer); if (!params.wb.enabled) { currWB = ColorTemp(); @@ -1141,9 +1144,9 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT double cam_r = colorMatrix[0][0] * camwbRed + colorMatrix[0][1] * camwbGreen + colorMatrix[0][2] * camwbBlue; double cam_g = colorMatrix[1][0] * camwbRed + colorMatrix[1][1] * camwbGreen + colorMatrix[1][2] * camwbBlue; double cam_b = colorMatrix[2][0] * camwbRed + colorMatrix[2][1] * camwbGreen + colorMatrix[2][2] * camwbBlue; - currWB = ColorTemp (cam_r, cam_g, cam_b, params.wb.equal); + currWB = ColorTemp (cam_r, cam_g, cam_b, params.wb.equal, params.wb.observer); } else if (params.wb.method == "autold") { - currWB = ColorTemp (autoWBTemp, autoWBGreen, wbEqual, "Custom"); + currWB = ColorTemp (autoWBTemp, autoWBGreen, wbEqual, "Custom", wbObserver); } double rm, gm, bm; @@ -1588,27 +1591,28 @@ void Thumbnail::getDimensions (int& w, int& h, double& scaleFac) } } -void Thumbnail::getCamWB (double& temp, double& green) +void Thumbnail::getCamWB (double& temp, double& green, StandardObserver observer) { double cam_r = colorMatrix[0][0] * camwbRed + colorMatrix[0][1] * camwbGreen + colorMatrix[0][2] * camwbBlue; double cam_g = colorMatrix[1][0] * camwbRed + colorMatrix[1][1] * camwbGreen + colorMatrix[1][2] * camwbBlue; double cam_b = colorMatrix[2][0] * camwbRed + colorMatrix[2][1] * camwbGreen + colorMatrix[2][2] * camwbBlue; - ColorTemp currWB = ColorTemp (cam_r, cam_g, cam_b, 1.0); // we do not take the equalizer into account here, because we want camera's WB + ColorTemp currWB = ColorTemp (cam_r, cam_g, cam_b, 1.0, observer); // we do not take the equalizer into account here, because we want camera's WB temp = currWB.getTemp (); green = currWB.getGreen (); } -void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tempBias) +void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tempBias, StandardObserver observer) { - if (equal != wbEqual || tempBias != wbTempBias) { + if (equal != wbEqual || tempBias != wbTempBias || observer != wbObserver) { // compute the values depending on equal ColorTemp cTemp; wbEqual = equal; wbTempBias = tempBias; + wbObserver = observer; // compute autoWBTemp and autoWBGreen - cTemp.mul2temp (redAWBMul, greenAWBMul, blueAWBMul, wbEqual, autoWBTemp, autoWBGreen); + cTemp.mul2temp (redAWBMul, greenAWBMul, blueAWBMul, wbEqual, wbObserver, autoWBTemp, autoWBGreen); autoWBTemp += autoWBTemp * tempBias; } @@ -1665,7 +1669,7 @@ void Thumbnail::getSpotWB (const procparams::ProcParams& params, int xp, int yp, double gm = colorMatrix[1][0] * reds + colorMatrix[1][1] * greens + colorMatrix[1][2] * blues; double bm = colorMatrix[2][0] * reds + colorMatrix[2][1] * greens + colorMatrix[2][2] * blues; - ColorTemp ct (rm, gm, bm, params.wb.equal); + ColorTemp ct (rm, gm, bm, params.wb.equal, params.wb.observer); rtemp = ct.getTemp (); rgreen = ct.getGreen (); } diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index 6ec1dfb34..535613ca2 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -38,6 +38,8 @@ class ustring; namespace rtengine { +enum class StandardObserver; + class Thumbnail { @@ -55,6 +57,7 @@ class Thumbnail double camwbBlue; double redAWBMul, greenAWBMul, blueAWBMul; // multipliers for auto WB double autoWBTemp, autoWBGreen, wbEqual, wbTempBias; // autoWBTemp and autoWBGreen are updated each time autoWB is requested and if wbEqual has been modified + StandardObserver wbObserver; LUTu aeHistogram; int aeHistCompression; bool aeValid; @@ -95,12 +98,12 @@ public: void getDimensions (int& w, int& h, double& scaleFac); static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false, bool forHistogramMatching = false); - static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching = false); - static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode = false); + static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, bool forHistogramMatching = false); + static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool inspectorMode = false); static RawMetaDataLocation loadMetaDataFromRaw (const Glib::ustring& fname); - void getCamWB (double& temp, double& green); - void getAutoWB (double& temp, double& green, double equal, double tempBias); + void getCamWB (double& temp, double& green, StandardObserver observer); + void getAutoWB (double& temp, double& green, double equal, double tempBias, StandardObserver observer); void getAutoWBMultipliers (double& rm, double& gm, double& bm); void getSpotWB (const procparams::ProcParams& params, int x, int y, int rect, double& temp, double& green); void applyAutoExp (procparams::ProcParams& pparams); diff --git a/rtengine/settings.h b/rtengine/settings.h index 1c8c73630..c920a355d 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -48,6 +48,8 @@ public: bool verbose; Glib::ustring darkFramesPath; ///< The default directory for dark frames Glib::ustring flatFieldsPath; ///< The default directory for flat fields + Glib::ustring cameraProfilesPath; ///< The default directory for camera profiles + Glib::ustring lensProfilesPath; ///< The default directory for lens profiles Glib::ustring adobe; // filename of AdobeRGB1998 profile (default to the bundled one) Glib::ustring prophoto; // filename of Prophoto profile (default to the bundled one) @@ -92,16 +94,7 @@ public: int previewselection; double cbdlsensi; // bool showtooltip; - - int itcwb_thres; - bool itcwb_sort; - int itcwb_greenrange; - int itcwb_greendeltatemp; - bool itcwb_forceextra; - int itcwb_sizereference; - int itcwb_delta; - bool itcwb_stdobserver10; - int itcwb_precis; + bool itcwb_enable; //wavelet levels double edghi; double edglo; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index c542cf726..78dd84042 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) { @@ -269,7 +269,7 @@ private: } // set the color temperature - currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); + currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method, params.wb.observer); if (!params.wb.enabled) { currWB = ColorTemp(); @@ -278,7 +278,7 @@ private: } else if (params.wb.method == "autold") { double rm, gm, bm; imgsrc->getAutoWBMultipliers(rm, gm, bm); - currWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias); + currWB.update(rm, gm, bm, params.wb.equal, params.wb.observer, params.wb.tempBias); } calclum = nullptr ; @@ -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); @@ -781,7 +781,7 @@ private: if (params.toneCurve.histmatching) { if (!params.toneCurve.fromHistMatching) { - imgsrc->getAutoMatchedToneCurve(params.icm, params.toneCurve.curve); + imgsrc->getAutoMatchedToneCurve(params.icm, params.wb.observer, params.toneCurve.curve); } if (params.toneCurve.autoexp) { 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..411b1de32 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -187,13 +187,13 @@ int StdImageSource::load (const Glib::ustring &fname) plistener->setProgress (1.0); } - wb = ColorTemp (1.0, 1.0, 1.0, 1.0); + wb = ColorTemp (1.0, 1.0, 1.0, 1.0, ColorTemp::DEFAULT_OBSERVER); //this is probably a mistake if embedded profile is not D65 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; @@ -348,7 +348,7 @@ void StdImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) blueAWBMul = bm; } -ColorTemp StdImageSource::getSpotWB (std::vector &red, std::vector &green, std::vector& blue, int tran, double equal) +ColorTemp StdImageSource::getSpotWB (std::vector &red, std::vector &green, std::vector& blue, int tran, double equal, StandardObserver observer) { int rn, gn, bn; double reds, greens, blues; @@ -360,13 +360,27 @@ ColorTemp StdImageSource::getSpotWB (std::vector &red, std::vectorallocate(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 f83c58a04..33a5a3667 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -58,16 +58,16 @@ 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 getrgbloc (int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) 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, const procparams::WBParams & wbpar) override {}; ColorTemp getWB () const override { return wb; } 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; + ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal, StandardObserver observer) 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;} @@ -123,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/rtgui/addsetids.h b/rtgui/addsetids.h index 8a2ae0466..d0d24fa76 100644 --- a/rtgui/addsetids.h +++ b/rtgui/addsetids.h @@ -68,6 +68,8 @@ enum { ADDSET_CAT_CHROMA_S, ADDSET_CAT_CHROMA_M, ADDSET_CAT_HUE, + ADDSET_CAT_DEGREEOUT, + ADDSET_CAT_TEMPOUT, ADDSET_CAT_BADPIX, ADDSET_WB_EQUAL, ADDSET_GRADIENT_DEGREE, diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 19da96fb5..4e25475f0 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 9fe4dd605..7499fb63b 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -201,6 +201,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/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 82f47b619..4383ccb74 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -148,7 +148,7 @@ void BatchToolPanelCoordinator::initSession () whitebalance->setAdjusterBehavior (false, false, false, false); vibrance->setAdjusterBehavior (false, false); vignetting->setAdjusterBehavior (false, false, false, false); - colorappearance->setAdjusterBehavior (false, false, false, false, false, false, false, false, false, false, false, false, false); + colorappearance->setAdjusterBehavior (false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); rotate->setAdjusterBehavior (false); resize->setAdjusterBehavior (false); distortion->setAdjusterBehavior (false); @@ -193,7 +193,7 @@ void BatchToolPanelCoordinator::initSession () whitebalance->setAdjusterBehavior (options.baBehav[ADDSET_WB_TEMPERATURE], options.baBehav[ADDSET_WB_GREEN], options.baBehav[ADDSET_WB_EQUAL], options.baBehav[ADDSET_WB_TEMPBIAS]); vibrance->setAdjusterBehavior (options.baBehav[ADDSET_VIBRANCE_PASTELS], options.baBehav[ADDSET_VIBRANCE_SATURATED]); vignetting->setAdjusterBehavior (options.baBehav[ADDSET_VIGN_AMOUNT], options.baBehav[ADDSET_VIGN_RADIUS], options.baBehav[ADDSET_VIGN_STRENGTH], options.baBehav[ADDSET_VIGN_CENTER]); - colorappearance->setAdjusterBehavior (options.baBehav[ADDSET_CAT_DEGREE], options.baBehav[ADDSET_CAT_ADAPTSCENE], options.baBehav[ADDSET_CAT_ADAPTVIEWING], options.baBehav[ADDSET_CAT_BADPIX], options.baBehav[ADDSET_CAT_LIGHT], options.baBehav[ADDSET_CAT_CHROMA], options.baBehav[ADDSET_CAT_CONTRAST], options.baBehav[ADDSET_CAT_RSTPRO], options.baBehav[ADDSET_CAT_BRIGHT], options.baBehav[ADDSET_CAT_CONTRAST_Q], options.baBehav[ADDSET_CAT_CHROMA_S], options.baBehav[ADDSET_CAT_CHROMA_M], options.baBehav[ADDSET_CAT_HUE]); + colorappearance->setAdjusterBehavior (options.baBehav[ADDSET_CAT_DEGREE], options.baBehav[ADDSET_CAT_ADAPTSCENE], options.baBehav[ADDSET_CAT_ADAPTVIEWING], options.baBehav[ADDSET_CAT_BADPIX], options.baBehav[ADDSET_CAT_LIGHT], options.baBehav[ADDSET_CAT_CHROMA], options.baBehav[ADDSET_CAT_CONTRAST], options.baBehav[ADDSET_CAT_RSTPRO], options.baBehav[ADDSET_CAT_BRIGHT], options.baBehav[ADDSET_CAT_CONTRAST_Q], options.baBehav[ADDSET_CAT_CHROMA_S], options.baBehav[ADDSET_CAT_CHROMA_M], options.baBehav[ADDSET_CAT_HUE],options.baBehav[ADDSET_CAT_DEGREEOUT], options.baBehav[ADDSET_CAT_TEMPOUT] ); rotate->setAdjusterBehavior (options.baBehav[ADDSET_ROTATE_DEGREE]); resize->setAdjusterBehavior (options.baBehav[ADDSET_RESIZE_SCALE]); distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]); @@ -293,6 +293,8 @@ void BatchToolPanelCoordinator::initSession () if (options.baBehav[ADDSET_CAT_CONTRAST]) { pparams.colorappearance.contrast = 0; } if (options.baBehav[ADDSET_CAT_CONTRAST_Q]) { pparams.colorappearance.qcontrast = 0; } if (options.baBehav[ADDSET_CAT_HUE]) { pparams.colorappearance.colorh = 0; } + if (options.baBehav[ADDSET_CAT_DEGREEOUT]) { pparams.colorappearance.degreeout = 0; } + if (options.baBehav[ADDSET_CAT_TEMPOUT]) { pparams.colorappearance.tempout = 0; } //if (options.baBehav[ADDSET_CBOOST_AMOUNT]) pparams.colorBoost.amount = 0; //if (options.baBehav[ADDSET_CS_BLUEYELLOW]) pparams.colorShift.a = 0; //if (options.baBehav[ADDSET_CS_GREENMAGENTA]) pparams.colorShift.b = 0; @@ -590,19 +592,19 @@ void BatchToolPanelCoordinator::unsetTweakOperator (rtengine::TweakOperator *tOp { } -void BatchToolPanelCoordinator::getAutoWB (double& temp, double& green, double equal, double tempBias) +void BatchToolPanelCoordinator::getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) { if (!selected.empty()) { - selected[0]->getAutoWB (temp, green, equal, tempBias); + selected[0]->getAutoWB (temp, green, equal, observer, tempBias); } } -void BatchToolPanelCoordinator::getCamWB (double& temp, double& green) +void BatchToolPanelCoordinator::getCamWB (double& temp, double& green, rtengine::StandardObserver observer) { if (!selected.empty()) { - selected[0]->getCamWB (temp, green); + selected[0]->getCamWB (temp, green, observer); } } diff --git a/rtgui/batchtoolpanelcoord.h b/rtgui/batchtoolpanelcoord.h index 0009724e8..f421793ac 100644 --- a/rtgui/batchtoolpanelcoord.h +++ b/rtgui/batchtoolpanelcoord.h @@ -69,8 +69,8 @@ public: ) override; // wbprovider interface - void getAutoWB (double& temp, double& green, double equal, double tempBias) override; - void getCamWB (double& temp, double& green) override; + void getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) override; + void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) override; // thumbnaillistener interface void procParamsChanged (Thumbnail* thm, int whoChangedIt) override; diff --git a/rtgui/checkbox.cc b/rtgui/checkbox.cc index e05ba061a..265123b23 100644 --- a/rtgui/checkbox.cc +++ b/rtgui/checkbox.cc @@ -80,7 +80,7 @@ void CheckBox::setValue (CheckValue newValue) break; case CheckValue::off: set_inconsistent (false); - set_active(true); + set_active(false); lastActive = false; break; case CheckValue::unchanged: diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index 5531a55c8..41f6952a7 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -662,7 +662,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, TOOL_NAME, M ("TP // Gtk::Image* iblueredL = Gtk::manage (new RTImage ("circle-blue-small.png")); // Gtk::Image* iblueredR = Gtk::manage (new RTImage ("circle-red-small.png")); - degreeout = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CIECAT_DEGREE"), 0., 100., 1., 90.)); + degreeout = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CIECAT_DEGREEOUT"), 0., 100., 1., 90.)); // degreeout->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); @@ -683,9 +683,9 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, TOOL_NAME, M ("TP ybout->set_tooltip_markup (M ("TP_COLORAPP_YBOUT_TOOLTIP")); tempout->set_tooltip_markup (M ("TP_COLORAPP_TEMP2_TOOLTIP")); - tempout->throwOnButtonRelease(); +// 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 + // 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(); @@ -696,8 +696,8 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, TOOL_NAME, M ("TP tempgreenVBox = Gtk::manage ( new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); tempgreenVBox->set_spacing (2); tempgreenVBox->pack_start (*tempout); - tempgreenVBox->pack_start (*greenout); - tempgreenFrame->add(*tempgreenVBox); + tempgreenVBox->pack_start (*greenout); + tempgreenFrame->add(*tempgreenVBox); p3VBox->pack_start(*tempgreenFrame); p3VBox->pack_start (*ybout); @@ -832,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); @@ -893,6 +893,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) if (pedited) { degree->setEditedState (pedited->colorappearance.degree ? Edited : UnEdited); degreeout->setEditedState (pedited->colorappearance.degreeout ? Edited : UnEdited); + tempout->setEditedState (pedited->colorappearance.tempout ? Edited : UnEdited); adapscen->setEditedState (pedited->colorappearance.adapscen ? Edited : UnEdited); ybscen->setEditedState (pedited->colorappearance.ybscen ? Edited : UnEdited); adaplum->setEditedState (pedited->colorappearance.adaplum ? Edited : UnEdited); @@ -1131,7 +1132,7 @@ 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); @@ -1483,12 +1484,14 @@ 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); + tempout->setAutoValue (true); + } else { + tempout->resetValue (false); + tempout->setValue (nexttemp); + tempout->setAutoValue (true); + } greenout->setValue (nextgreen); enableListener(); @@ -1515,6 +1518,7 @@ void ColorAppearance::catmethodChanged() degreeout->resetValue (false); ybout->resetValue (false); tempout->resetValue (false); + tempout->setAutoValue (true); greenout->resetValue (false); enableListener(); } else if (catmethod->get_active_row_number() == 2) { @@ -2311,7 +2315,7 @@ void ColorAppearance::updateCurveBackgroundHistogram( -void ColorAppearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd) +void ColorAppearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd, bool degreeoutadd, bool tempoutadd) { degree->setAddMode (degreeadd); @@ -2327,6 +2331,9 @@ void ColorAppearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, boo contrast->setAddMode (contrastadd); qcontrast->setAddMode (qcontrastadd); colorh->setAddMode (colorhadd); + degreeout->setAddMode (degreeoutadd); + tempout->setAddMode (tempoutadd); + } void ColorAppearance::trimValues (rtengine::procparams::ProcParams* pp) diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index dcf19b977..714f3e557 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -88,7 +88,7 @@ public: bool isCurveExpanded (); void autoOpenCurve () override; - void setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd); + void setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd, bool degreeoutadd, bool tempoutadd); void trimValues (rtengine::procparams::ProcParams* pp) override; void updateCurveBackgroundHistogram( const LUTu& histToneCurve, diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 95808d4b0..ffe13fea3 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2013,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), @@ -2270,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") { @@ -2380,7 +2380,7 @@ 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"); diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc index 292fa98ae..4f1ae9311 100644 --- a/rtgui/filmnegative.cc +++ b/rtgui/filmnegative.cc @@ -33,6 +33,12 @@ const Glib::ustring FilmNegative::TOOL_NAME = "filmnegative"; namespace { +/** + * Observer to use for displaying the temperature and tint equivalent of the + * multipliers. + */ +constexpr rtengine::StandardObserver standard_observer = rtengine::ColorTemp::DEFAULT_OBSERVER; + double toAdjuster(double v) { return CLAMP(std::log2(v), 6, 16) - 6; @@ -154,7 +160,7 @@ RGB getFilmNegativeExponents(const RGB &ref1, const RGB &ref2) // , const RGB &c void temp2rgb(double outLev, double temp, double green, RGB &refOut) { - rtengine::ColorTemp ct = rtengine::ColorTemp(temp, green, 1., "Custom"); + rtengine::ColorTemp ct = rtengine::ColorTemp(temp, green, 1., "Custom", standard_observer); double rm, gm, bm; ct.getMultipliers(rm, gm, bm); @@ -175,7 +181,8 @@ void rgb2temp(const RGB &refOut, double &outLev, double &temp, double &green) refOut.r / maxVal, refOut.g / maxVal, refOut.b / maxVal, - 1.); + 1., + standard_observer); outLev = maxVal; temp = ct.getTemp(); @@ -188,7 +195,7 @@ void rgb2temp(const RGB &refOut, double &outLev, double &temp, double &green) FilmNegative::FilmNegative() : FoldableToolPanel(this, TOOL_NAME, M("TP_FILMNEGATIVE_LABEL"), false, true), EditSubscriber(ET_OBJECTS), - NEUTRAL_TEMP(rtengine::ColorTemp(1., 1., 1., 1.)), + NEUTRAL_TEMP(rtengine::ColorTemp(1., 1., 1., 1., rtengine::ColorTemp::DEFAULT_OBSERVER)), evFilmNegativeExponents(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_VALUES")), evFilmNegativeEnabled(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_ENABLED")), evFilmNegativeRefSpot(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_REF_SPOT")), diff --git a/rtgui/options.cc b/rtgui/options.cc index 3ce97567c..b59e7c203 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"; @@ -569,6 +570,9 @@ void Options::setDefaults() rtSettings.darkFramesPath = ""; rtSettings.flatFieldsPath = ""; + rtSettings.cameraProfilesPath = ""; + rtSettings.lensProfilesPath = ""; + #ifdef WIN32 const gchar* sysRoot = g_getenv("SystemRoot"); // Returns e.g. "c:\Windows" @@ -621,17 +625,8 @@ void Options::setDefaults() rtSettings.previewselection = 5;//between 1 to 40 rtSettings.cbdlsensi = 1.0;//between 0.001 to 1 rtSettings.fftwsigma = true; //choice between sigma^2 or empirical formula - - rtSettings.itcwb_thres = 34;//between 10 to 55 - rtSettings.itcwb_sort = false; - rtSettings.itcwb_greenrange = 0;//between 0 to 2 - 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 // end locallab + rtSettings.itcwb_enable = true; //wavelet rtSettings.edghi = 3.0;//1.1 and 5. @@ -659,13 +654,15 @@ void Options::setDefaults() rtSettings.leveldnliss = 0; rtSettings.leveldnautsimpl = 0; -// rtSettings.colortoningab =0.7; -//rtSettings.decaction =0.3; +// rtSettings.colortoningab =0.7; +// rtSettings.decaction =0.3; // rtSettings.ciebadpixgauss=false; rtSettings.rgbcurveslumamode_gamut = true; lastIccDir = rtSettings.iccDirectory; lastDarkframeDir = rtSettings.darkFramesPath; lastFlatfieldDir = rtSettings.flatFieldsPath; + lastCameraProfilesDir = rtSettings.cameraProfilesPath; + lastLensProfilesDir = rtSettings.lensProfilesPath; // rtSettings.bw_complementary = true; // There is no reasonable default for curves. We can still suppose that they will take place // in a subdirectory of the user's own ProcParams presets, i.e. in a subdirectory @@ -799,6 +796,14 @@ void Options::readFromFile(Glib::ustring fname) rtSettings.flatFieldsPath = keyFile.get_string("General", "FlatFieldsPath"); } + if (keyFile.has_key("General", "CameraProfilesPath")) { + rtSettings.cameraProfilesPath = keyFile.get_string("General", "CameraProfilesPath"); + } + + if (keyFile.has_key("General", "LensProfilesPath")) { + rtSettings.lensProfilesPath = keyFile.get_string("General", "LensProfilesPath"); + } + if (keyFile.has_key("General", "Verbose")) { rtSettings.verbose = keyFile.get_boolean("General", "Verbose"); } @@ -1044,6 +1049,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"); } @@ -1791,41 +1800,10 @@ void Options::readFromFile(Glib::ustring fname) rtSettings.level123_cbdl = keyFile.get_double("Color Management", "CBDLlevel123"); } - if (keyFile.has_key("Color Management", "Itcwb_thres")) { - rtSettings.itcwb_thres = keyFile.get_integer("Color Management", "Itcwb_thres"); + if (keyFile.has_key("Color Management", "Itcwb_enable")) { + rtSettings.itcwb_enable = keyFile.get_boolean("Color Management", "Itcwb_enable"); } - 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_forceextra")) { - rtSettings.itcwb_forceextra = keyFile.get_boolean("Color Management", "Itcwb_forceextra"); - } - - if (keyFile.has_key("Color Management", "Itcwb_stdobserver10")) { - rtSettings.itcwb_stdobserver10 = keyFile.get_boolean("Color Management", "Itcwb_stdobserver10"); - } - - if (keyFile.has_key("Color Management", "Itcwb_greenrange")) { - rtSettings.itcwb_greenrange = keyFile.get_integer("Color Management", "Itcwb_greenrange"); - } - - if (keyFile.has_key("Color Management", "Itcwb_greendeltatemp")) { - rtSettings.itcwb_greendeltatemp = keyFile.get_integer("Color Management", "Itcwb_greendeltatemp"); - } - - if (keyFile.has_key("Color Management", "Itcwb_sizereference")) { - rtSettings.itcwb_sizereference = keyFile.get_integer("Color Management", "Itcwb_sizereference"); - } - - if (keyFile.has_key("Color Management", "Itcwb_delta")) { - rtSettings.itcwb_delta = keyFile.get_integer("Color Management", "Itcwb_delta"); - } - - if (keyFile.has_key("Color Management", "Itcwb_precis")) { - rtSettings.itcwb_precis = keyFile.get_integer("Color Management", "Itcwb_precis"); - } //if (keyFile.has_key ("Color Management", "Colortoningab")) rtSettings.colortoningab = keyFile.get_double("Color Management", "Colortoningab"); //if (keyFile.has_key ("Color Management", "Decaction")) rtSettings.decaction = keyFile.get_double("Color Management", "Decaction"); @@ -2223,6 +2201,8 @@ void Options::readFromFile(Glib::ustring fname) safeDirGet(keyFile, "Dialogs", "LastIccDir", lastIccDir); safeDirGet(keyFile, "Dialogs", "LastDarkframeDir", lastDarkframeDir); safeDirGet(keyFile, "Dialogs", "LastFlatfieldDir", lastFlatfieldDir); + safeDirGet(keyFile, "Dialogs", "LastCameraProfilesDir", lastCameraProfilesDir); + safeDirGet(keyFile, "Dialogs", "LastLensProfilesDir", lastLensProfilesDir); safeDirGet(keyFile, "Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); safeDirGet(keyFile, "Dialogs", "LastLabCurvesDir", lastLabCurvesDir); safeDirGet(keyFile, "Dialogs", "LastRetinexDir", lastRetinexDir); @@ -2326,6 +2306,8 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("General", "Version", RTVERSION); keyFile.set_string("General", "DarkFramesPath", rtSettings.darkFramesPath); keyFile.set_string("General", "FlatFieldsPath", rtSettings.flatFieldsPath); + keyFile.set_string("General", "CameraProfilesPath", rtSettings.cameraProfilesPath); + keyFile.set_string("General", "LensProfilesPath", rtSettings.lensProfilesPath); keyFile.set_boolean("General", "Verbose", rtSettings.verbose); keyFile.set_integer("General", "Cropsleep", rtSettings.cropsleep); keyFile.set_double("General", "Reduchigh", rtSettings.reduchigh); @@ -2437,6 +2419,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); @@ -2595,15 +2578,7 @@ void Options::saveToFile(Glib::ustring fname) //keyFile.set_boolean ("Color Management", "Ciebadpixgauss", rtSettings.ciebadpixgauss); 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_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_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); - keyFile.set_integer("Color Management", "Itcwb_precis", rtSettings.itcwb_precis); + keyFile.set_boolean("Color Management", "Itcwb_enable", rtSettings.itcwb_enable); //keyFile.set_double ("Color Management", "Colortoningab", rtSettings.colortoningab); //keyFile.set_double ("Color Management", "Decaction", rtSettings.decaction); @@ -2682,6 +2657,8 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("Dialogs", "LastIccDir", lastIccDir); keyFile.set_string("Dialogs", "LastDarkframeDir", lastDarkframeDir); keyFile.set_string("Dialogs", "LastFlatfieldDir", lastFlatfieldDir); + keyFile.set_string("Dialogs", "LastCameraProfilesDir", lastCameraProfilesDir); + keyFile.set_string("Dialogs", "LastLensProfilesDir", lastLensProfilesDir); keyFile.set_string("Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); keyFile.set_string("Dialogs", "LastLabCurvesDir", lastLabCurvesDir); keyFile.set_string("Dialogs", "LastRetinexDir", lastRetinexDir); diff --git a/rtgui/options.h b/rtgui/options.h index 286c64df0..2c34260aa 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -72,6 +72,7 @@ struct SaveFormat { int _tiff_bits, bool _tiff_float, bool _tiff_uncompressed, + bool _big_tiff, bool _save_params ) : format(_format), @@ -81,6 +82,7 @@ struct SaveFormat { tiffBits(_tiff_bits), tiffFloat(_tiff_float), tiffUncompressed(_tiff_uncompressed), + bigTiff(_big_tiff), saveParams(_save_params) { } @@ -98,6 +100,7 @@ struct SaveFormat { _tiff_bits, _tiff_float, true, + false, true ) { @@ -114,6 +117,7 @@ struct SaveFormat { int tiffBits; bool tiffFloat; bool tiffUncompressed; + bool bigTiff; bool saveParams; }; @@ -446,6 +450,8 @@ public: Glib::ustring lastIccDir; Glib::ustring lastDarkframeDir; Glib::ustring lastFlatfieldDir; + Glib::ustring lastCameraProfilesDir; + Glib::ustring lastLensProfilesDir; Glib::ustring lastRgbCurvesDir; Glib::ustring lastLabCurvesDir; Glib::ustring lastRetinexDir; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 952ffcff6..adf462d84 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; @@ -265,6 +266,17 @@ void ParamsEdited::set(bool v) wb.temperature = v; wb.equal = v; wb.tempBias = v; + wb.observer = v; + wb.itcwb_thres = v; + wb.itcwb_precis = v; + wb.itcwb_size = v; + wb.itcwb_delta = v; + wb.itcwb_fgreen = v; + wb.itcwb_rgreen = v; + wb.itcwb_nopurple = v; + wb.itcwb_sorted = v; + wb.itcwb_forceextra = v; + wb.itcwb_sampling = v; //colorShift.a = v; //colorShift.b = v; //lumaDenoise.enabled = v; @@ -754,6 +766,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; @@ -970,6 +983,17 @@ void ParamsEdited::initFrom(const std::vector& wb.equal = wb.equal && p.wb.equal == other.wb.equal; wb.temperature = wb.temperature && p.wb.temperature == other.wb.temperature; wb.tempBias = wb.tempBias && p.wb.tempBias == other.wb.tempBias; + wb.observer = wb.observer && p.wb.observer == other.wb.observer; + wb.itcwb_thres = wb.itcwb_thres && p.wb.itcwb_thres == other.wb.itcwb_thres; + wb.itcwb_precis = wb.itcwb_precis && p.wb.itcwb_precis == other.wb.itcwb_precis; + wb.itcwb_size = wb.itcwb_size && p.wb.itcwb_size == other.wb.itcwb_size; + wb.itcwb_delta = wb.itcwb_delta && p.wb.itcwb_delta == other.wb.itcwb_delta; + wb.itcwb_fgreen = wb.itcwb_fgreen && p.wb.itcwb_fgreen == other.wb.itcwb_fgreen; + wb.itcwb_rgreen = wb.itcwb_rgreen && p.wb.itcwb_rgreen == other.wb.itcwb_rgreen; + wb.itcwb_nopurple = wb.itcwb_nopurple && p.wb.itcwb_nopurple == other.wb.itcwb_nopurple; + wb.itcwb_sorted = wb.itcwb_sorted && p.wb.itcwb_sorted == other.wb.itcwb_sorted; + wb.itcwb_forceextra = wb.itcwb_forceextra && p.wb.itcwb_forceextra == other.wb.itcwb_forceextra; + wb.itcwb_sampling = wb.itcwb_sampling && p.wb.itcwb_sampling == other.wb.itcwb_sampling; //colorShift.a = colorShift.a && p.colorShift.a == other.colorShift.a; //colorShift.b = colorShift.b && p.colorShift.b == other.colorShift.b; //lumaDenoise.enabled = lumaDenoise.enabled && p.lumaDenoise.enabled == other.lumaDenoise.enabled; @@ -2205,6 +2229,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; } @@ -2836,6 +2864,50 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wb.tempBias = dontforceSet && options.baBehav[ADDSET_WB_TEMPBIAS] ? toEdit.wb.tempBias + mods.wb.tempBias : mods.wb.tempBias; } + if (wb.observer) { + toEdit.wb.observer = mods.wb.observer; + } + + if (wb.itcwb_thres) { + toEdit.wb.itcwb_thres = mods.wb.itcwb_thres; + } + + if (wb.itcwb_precis) { + toEdit.wb.itcwb_precis = mods.wb.itcwb_precis; + } + + if (wb.itcwb_size) { + toEdit.wb.itcwb_size = mods.wb.itcwb_size; + } + + if (wb.itcwb_delta) { + toEdit.wb.itcwb_delta = mods.wb.itcwb_delta; + } + + if (wb.itcwb_fgreen) { + toEdit.wb.itcwb_fgreen = mods.wb.itcwb_fgreen; + } + + if (wb.itcwb_rgreen) { + toEdit.wb.itcwb_rgreen = mods.wb.itcwb_rgreen; + } + + if (wb.itcwb_nopurple) { + toEdit.wb.itcwb_nopurple = mods.wb.itcwb_nopurple; + } + + if (wb.itcwb_sorted) { + toEdit.wb.itcwb_sorted = mods.wb.itcwb_sorted; + } + + if (wb.itcwb_forceextra) { + toEdit.wb.itcwb_forceextra = mods.wb.itcwb_forceextra; + } + + if (wb.itcwb_sampling) { + toEdit.wb.itcwb_sampling = mods.wb.itcwb_sampling; + } + if (wb.green) { toEdit.wb.green = dontforceSet && options.baBehav[ADDSET_WB_GREEN] ? toEdit.wb.green + mods.wb.green : mods.wb.green; } @@ -2917,7 +2989,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng } if (colorappearance.degreeout) { - toEdit.colorappearance.degreeout = mods.colorappearance.degreeout; + toEdit.colorappearance.degreeout = dontforceSet && options.baBehav[ADDSET_CAT_DEGREEOUT] ? toEdit.colorappearance.degreeout + mods.colorappearance.degreeout : mods.colorappearance.degreeout; } if (colorappearance.autodegreeout) { @@ -2969,7 +3041,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng } if (colorappearance.tempout) { - toEdit.colorappearance.tempout = mods.colorappearance.tempout; + toEdit.colorappearance.tempout = dontforceSet && options.baBehav[ADDSET_CAT_TEMPOUT] ? toEdit.colorappearance.tempout + mods.colorappearance.tempout : mods.colorappearance.tempout; } if (colorappearance.autotempout) { diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 5a50d0da4..3c8a70b74 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -53,6 +53,7 @@ struct ToneCurveParamsEdited { bool shcompr; bool hlcompr; bool hlbl; + bool hlth; bool hlcomprthresh; bool autoexp; bool clip; @@ -246,7 +247,19 @@ struct WBParamsEdited { bool temperature; bool green; bool equal; + bool observer; bool tempBias; + bool itcwb_thres; + bool itcwb_precis; + bool itcwb_size; + bool itcwb_delta; + bool itcwb_fgreen; + bool itcwb_rgreen; + bool itcwb_nopurple; + bool itcwb_sorted; + bool itcwb_forceextra; + bool itcwb_sampling; + }; struct DefringeParamsEdited { diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h index 162e63f9e..f2455699c 100644 --- a/rtgui/ppversion.h +++ b/rtgui/ppversion.h @@ -1,11 +1,13 @@ #pragma once // This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes -#define PPVERSION 349 +#define PPVERSION 350 #define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified /* Log of version changes + 350 2023-03-05 + introduced white balance standard observer 349 2020-10-29 replaced Haze removal Luminance checkbox with an adjuster to blend between luminance and normal mode 348 2018-09-25 diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 8f65bff0f..e33be4483 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -297,15 +297,18 @@ Gtk::Widget* Preferences::getBatchProcPanel() mi->set_value(behavColumns.label, M("TP_COLORAPP_LABEL")); appendBehavList (mi, M("TP_COLORAPP_LABEL_SCENE") + " - " + M("TP_COLORAPP_ABSOLUTELUMINANCE"), ADDSET_CAT_ADAPTSCENE, true); appendBehavList (mi, M("TP_COLORAPP_LABEL_VIEWING") + " - " + M("TP_COLORAPP_ABSOLUTELUMINANCE"), ADDSET_CAT_ADAPTVIEWING, true); + appendBehavList(mi, M("TP_COLORAPP_CIECAT_DEGREE"), ADDSET_CAT_DEGREE, true); appendBehavList(mi, M("TP_COLORAPP_LIGHT"), ADDSET_CAT_LIGHT, true); appendBehavList(mi, M("TP_COLORAPP_BRIGHT"), ADDSET_CAT_BRIGHT, true); appendBehavList(mi, M("TP_COLORAPP_CHROMA"), ADDSET_CAT_CHROMA, true); - appendBehavList (mi, M ("TP_COLORAPP_CHROMA_S"), ADDSET_CAT_CHROMA_S, true); - appendBehavList (mi, M ("TP_COLORAPP_CHROMA_M"), ADDSET_CAT_CHROMA_M, true); + appendBehavList(mi, M ("TP_COLORAPP_CHROMA_S"), ADDSET_CAT_CHROMA_S, true); + appendBehavList(mi, M ("TP_COLORAPP_CHROMA_M"), ADDSET_CAT_CHROMA_M, true); appendBehavList(mi, M("TP_COLORAPP_RSTPRO"), ADDSET_CAT_RSTPRO, true); appendBehavList(mi, M("TP_COLORAPP_CONTRAST"), ADDSET_CAT_CONTRAST, true); appendBehavList(mi, M("TP_COLORAPP_CONTRAST_Q"), ADDSET_CAT_CONTRAST_Q, true); appendBehavList(mi, M("TP_COLORAPP_HUE"), ADDSET_CAT_HUE, true); + appendBehavList(mi, M("TP_COLORAPP_CIECAT_DEGREEOUT"), ADDSET_CAT_DEGREEOUT, true); + appendBehavList(mi, M("TP_WBALANCE_TEMPERATURE"), ADDSET_CAT_TEMPOUT, true); appendBehavList(mi, M("TP_COLORAPP_BADPIXSL"), ADDSET_CAT_BADPIX, true); mi = behModel->append(); @@ -612,6 +615,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () Gtk::Grid* dirgrid = Gtk::manage(new Gtk::Grid()); setExpandAlignProperties(dirgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + // Dark Frames Dir Gtk::Label *dfLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_DIRDARKFRAMES") + ":")); setExpandAlignProperties(dfLab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); darkFrameDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_DIRDARKFRAMES"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); @@ -625,7 +629,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () dfconn = darkFrameDir->signal_selection_changed().connect ( sigc::mem_fun (*this, &Preferences::darkFrameChanged)); - // FLATFIELD + // Flatfield Dir Gtk::Label *ffLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_FLATFIELDSDIR") + ":")); setExpandAlignProperties(ffLab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); flatFieldDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_FLATFIELDSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); @@ -651,6 +655,25 @@ Gtk::Widget* Preferences::getImageProcessingPanel () dirgrid->attach_next_to(*clutsDir, *clutsDirLabel, Gtk::POS_RIGHT, 1, 1); dirgrid->attach_next_to(*clutsRestartNeeded, *clutsDir, Gtk::POS_RIGHT, 1, 1); + //Camera Profiles Dir + Gtk::Label *cameraProfilesDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_CAMERAPROFILESDIR") + ":")); + setExpandAlignProperties(cameraProfilesDirLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + cameraProfilesDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_CAMERAPROFILESDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + setExpandAlignProperties(cameraProfilesDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + + dirgrid->attach_next_to(*cameraProfilesDirLabel, *clutsDirLabel, Gtk::POS_BOTTOM, 1, 1); + dirgrid->attach_next_to(*cameraProfilesDir, *cameraProfilesDirLabel, Gtk::POS_RIGHT, 1, 1); + + //Lens Profiles Dir + Gtk::Label *lensProfilesDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_LENSPROFILESDIR") + ":")); + setExpandAlignProperties(lensProfilesDirLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + lensProfilesDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_LENSPROFILESDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + setExpandAlignProperties(lensProfilesDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + + dirgrid->attach_next_to(*lensProfilesDirLabel, *cameraProfilesDirLabel, Gtk::POS_BOTTOM, 1, 1); + dirgrid->attach_next_to(*lensProfilesDir, *lensProfilesDirLabel, Gtk::POS_RIGHT, 1, 1); + + //Pack directories to Image Processing panel cdf->add(*dirgrid); vbImageProcessing->pack_start (*cdf, Gtk::PACK_SHRINK, 4 ); @@ -934,6 +957,10 @@ Gtk::Widget* Preferences::getColorManPanel () fcie->add(*gcie); vbColorMan->pack_start (*fcie, Gtk::PACK_SHRINK); + + + //------------- + swColorMan->add(*vbColorMan); return swColorMan; } @@ -1846,8 +1873,9 @@ void Preferences::storePreferences() moptions.rtSettings.darkFramesPath = darkFrameDir->get_filename(); moptions.rtSettings.flatFieldsPath = flatFieldDir->get_filename(); - moptions.clutsDir = clutsDir->get_filename(); + moptions.rtSettings.cameraProfilesPath = cameraProfilesDir->get_filename(); + moptions.rtSettings.lensProfilesPath = lensProfilesDir->get_filename(); moptions.baBehav.resize(ADDSET_PARAM_NUM); @@ -1960,6 +1988,7 @@ void Preferences::fillPreferences() monBPC->set_active(moptions.rtSettings.monitorBPC); mcie->set_active(moptions.rtSettings.autocielab); + cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile); #endif @@ -2103,6 +2132,10 @@ void Preferences::fillPreferences() flatFieldChanged(); clutsDir->set_current_folder(moptions.clutsDir); + + cameraProfilesDir->set_current_folder(moptions.rtSettings.cameraProfilesPath); + + lensProfilesDir->set_current_folder(moptions.rtSettings.lensProfilesPath); addc.block(true); setc.block(true); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 90ea20da7..6e31761a4 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -115,6 +115,8 @@ class Preferences final : MyFileChooserButton* darkFrameDir; MyFileChooserButton* flatFieldDir; MyFileChooserButton* clutsDir; + MyFileChooserButton* cameraProfilesDir; + MyFileChooserButton* lensProfilesDir; Gtk::Label *dfLabel; Gtk::Label *ffLabel; @@ -135,6 +137,15 @@ class Preferences final : Gtk::CheckButton* cbdaubech; Gtk::SpinButton* hlThresh; Gtk::SpinButton* shThresh; +// Gtk::CheckButton* mwbacorr; + // Gtk::CheckButton* mwbaforc; + // Gtk::CheckButton* mwbanopurp; + +// Gtk::CheckButton* mwbasort; +// Gtk::SpinButton* wbacorrnb; +// Gtk::SpinButton* wbaprecis; +// Gtk::SpinButton* wbasizeref; +// Gtk::SpinButton* wbagreendelta; Gtk::SpinButton* panFactor; Gtk::CheckButton* rememberZoomPanCheckbutton; @@ -240,7 +251,7 @@ class Preferences final : Options moptions; sigc::connection tconn, sconn, fconn, cpfconn, addc, setc, dfconn, ffconn, bpconn, rpconn, ipconn; - sigc::connection autoMonProfileConn, sndEnableConn, langAutoDetectConn, autocielabConn; + sigc::connection autoMonProfileConn, sndEnableConn, langAutoDetectConn, autocielabConn, observer10Conn; Glib::ustring initialTheme; Glib::ustring initialFontFamily; int initialFontSize; @@ -305,6 +316,7 @@ public: void sndEnableToggled (); void langAutoDetectToggled (); void autocielabToggled (); + void observer10Toggled (); void selectStartupDir (); void addExtPressed (); 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/thumbnail.cc b/rtgui/thumbnail.cc index 56cd82b46..96a8bf849 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -139,20 +139,20 @@ void Thumbnail::_generateThumbnailImage () if (ext == "jpg" || ext == "jpeg") { infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal, pparams->wb.observer); if (tpp) { cfs.format = FT_Jpeg; } } else if (ext == "png") { - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal, pparams->wb.observer); if (tpp) { cfs.format = FT_Png; } } else if (ext == "tif" || ext == "tiff") { infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal, pparams->wb.observer); if (tpp) { cfs.format = FT_Tiff; @@ -173,7 +173,7 @@ void Thumbnail::_generateThumbnailImage () if ( tpp == nullptr ) { quick = false; - tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams->wb.equal, TRUE); + tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams->wb.equal, pparams->wb.observer, TRUE); } cfs.sensortype = sensorType; @@ -216,11 +216,11 @@ const ProcParams& Thumbnail::getProcParamsU () if (pparams->wb.method == "Camera") { double ct; - getCamWB (ct, pparams->wb.green); + getCamWB (ct, pparams->wb.green, pparams->wb.observer); pparams->wb.temperature = ct; } else if (pparams->wb.method == "autold") { double ct; - getAutoWB (ct, pparams->wb.green, pparams->wb.equal, pparams->wb.tempBias); + getAutoWB (ct, pparams->wb.green, pparams->wb.equal, pparams->wb.observer, pparams->wb.tempBias); pparams->wb.temperature = ct; } } @@ -786,10 +786,10 @@ const Glib::DateTime& Thumbnail::getDateTime () const return dateTime; } -void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tempBias) +void Thumbnail::getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) { if (cfs.redAWBMul != -1.0) { - rtengine::ColorTemp ct(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul, equal); + rtengine::ColorTemp ct(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul, equal, observer); temp = ct.getTemp(); green = ct.getGreen(); } else { @@ -1156,10 +1156,10 @@ bool Thumbnail::imageLoad(bool loading) return false; } -void Thumbnail::getCamWB(double& temp, double& green) const +void Thumbnail::getCamWB(double& temp, double& green, rtengine::StandardObserver observer) const { if (tpp) { - tpp->getCamWB (temp, green); + tpp->getCamWB (temp, green, observer); } else { temp = green = -1.0; } diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 491151028..4d0355747 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -127,8 +127,8 @@ 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 getCamWB (double& temp, double& green, rtengine::StandardObserver observer) const; + void getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias); void getSpotWB (int x, int y, int rect, double& temp, double& green); void applyAutoExp (rtengine::procparams::ProcParams& pparams); diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index c39bd3bda..bf81c6f22 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -42,6 +42,7 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL 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); @@ -97,13 +98,14 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL 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); @@ -113,9 +115,11 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL 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); @@ -223,6 +227,7 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL black->setAdjusterListener(this); hlcompr->setAdjusterListener(this); hlbl->setAdjusterListener(this); + hlth->setAdjusterListener(this); hlcomprthresh->setAdjusterListener(this); shcompr->setAdjusterListener(this); contrast->setAdjusterListener(this); @@ -254,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); @@ -283,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); @@ -310,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(); @@ -354,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(); @@ -403,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(); @@ -414,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; @@ -428,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"; } } @@ -454,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(); } } @@ -487,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()) { @@ -513,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(); @@ -526,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); @@ -536,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); @@ -546,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); @@ -660,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); @@ -695,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); @@ -707,6 +738,7 @@ void ToneCurve::neutral_pressed() hlrbox->show(); hlrbox->set_sensitive(false); hlbl->hide(); + hlth->hide(); } if (!black->getAddMode() && !batchMode) { @@ -841,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); } @@ -853,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); @@ -864,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); } @@ -883,6 +918,7 @@ void ToneCurve::setBatchMode(bool batchMode) black->showEditedCB(); hlcompr->showEditedCB(); hlbl->showEditedCB(); + hlth->showEditedCB(); hlcomprthresh->showEditedCB(); shcompr->showEditedCB(); brightness->showEditedCB(); @@ -996,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 7ba2178ac..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; diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index bc1e1a2d3..95350c5e8 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -401,16 +401,16 @@ public: void updateShowtooltipVisibility (bool showtooltip); // wbprovider interface - void getAutoWB (double& temp, double& green, double equal, double tempBias) override + void getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) override { if (ipc) { - ipc->getAutoWB(temp, green, equal, tempBias); + ipc->getAutoWB(temp, green, equal, observer, tempBias); } } - void getCamWB (double& temp, double& green) override + void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) override { if (ipc) { - ipc->getCamWB(temp, green); + ipc->getCamWB(temp, green, observer); } } diff --git a/rtgui/wbprovider.h b/rtgui/wbprovider.h index a56d93cd3..514a71300 100644 --- a/rtgui/wbprovider.h +++ b/rtgui/wbprovider.h @@ -18,12 +18,19 @@ */ #pragma once +namespace rtengine +{ + +enum class StandardObserver; + +} + class WBProvider { public: virtual ~WBProvider() {} - virtual void getAutoWB (double& temp, double& green, double equal, double tempBias) {} - virtual void getCamWB (double& temp, double& green) {} + virtual void getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) {} + virtual void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) {} virtual void spotWBRequested (int size) {} }; diff --git a/rtgui/whitebalance.cc b/rtgui/whitebalance.cc index f6a26e335..761f2402a 100644 --- a/rtgui/whitebalance.cc +++ b/rtgui/whitebalance.cc @@ -22,6 +22,9 @@ #include "rtimage.h" #include "options.h" +#include "eventmapper.h" + +#include "../rtengine/colortemp.h" #define MINTEMP 1500 //1200 #define MAXTEMP 60000 //12000 @@ -242,6 +245,10 @@ WhiteBalance::WhiteBalance () : FoldableToolPanel(this, TOOL_NAME, M("TP_WBALANC custom_equal = 1.0; } + auto m = ProcEventMapper::getInstance(); + EvWBObserver10 = m->newEvent(ALLNORAW, "HISTORY_MSG_WBALANCE_OBSERVER10"); + + //Add the model columns to the Combo (which is a kind of view), //rendering them in the default way: method->pack_start(methodColumns.colIcon, false); @@ -336,26 +343,35 @@ WhiteBalance::WhiteBalance () : FoldableToolPanel(this, TOOL_NAME, M("TP_WBALANC StudLabel = Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER)); StudLabel->set_tooltip_text(M("TP_WBALANCE_STUDLABEL_TOOLTIP")); + mulLabel = Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER)); + mulLabel->set_tooltip_text(M("TP_WBALANCE_MULLABEL_TOOLTIP")); + mulLabel->show(); + temp = Gtk::manage (new Adjuster (M("TP_WBALANCE_TEMPERATURE"), MINTEMP, MAXTEMP, 5, CENTERTEMP, itempL, itempR, &wbSlider2Temp, &wbTemp2Slider)); green = Gtk::manage (new Adjuster (M("TP_WBALANCE_GREEN"), MINGREEN, MAXGREEN, 0.001, 1.0, igreenL, igreenR)); equal = Gtk::manage (new Adjuster (M("TP_WBALANCE_EQBLUERED"), MINEQUAL, MAXEQUAL, 0.001, 1.0, iblueredL, iblueredR)); tempBias = Gtk::manage (new Adjuster(M("TP_WBALANCE_TEMPBIAS"), -0.5, 0.5, 0.01, 0.0, itempbiasL, itempbiasR)); + observer10 = Gtk::manage(new CheckBox(M("TP_WBALANCE_OBSERVER10"), multiImage)); + cache_customTemp (0); cache_customGreen (0); cache_customEqual (0); equal->set_tooltip_markup (M("TP_WBALANCE_EQBLUERED_TOOLTIP")); tempBias->set_tooltip_markup (M("TP_WBALANCE_TEMPBIAS_TOOLTIP")); + observer10->set_tooltip_text(M("TP_WBALANCE_OBSERVER10_TOOLTIP")); temp->show (); green->show (); equal->show (); tempBias->show (); - + observer10->show(); + /* Gtk::Box* boxgreen = Gtk::manage (new Gtk::Box ()); boxgreen->show (); boxgreen->pack_start(*igreenL); boxgreen->pack_start(*green); boxgreen->pack_start(*igreenR);*/ + pack_start(*mulLabel); pack_start(*StudLabel); pack_start (*temp); @@ -363,11 +379,14 @@ WhiteBalance::WhiteBalance () : FoldableToolPanel(this, TOOL_NAME, M("TP_WBALANC pack_start (*green); pack_start (*equal); pack_start (*tempBias); + pack_start(*observer10); + temp->setAdjusterListener (this); green->setAdjusterListener (this); equal->setAdjusterListener (this); tempBias->setAdjusterListener (this); + observer10->setCheckBoxListener(this); spotbutton->signal_pressed().connect( sigc::mem_fun(*this, &WhiteBalance::spotPressed) ); methconn = method->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::optChanged) ); @@ -394,6 +413,8 @@ void WhiteBalance::enabledChanged() } + + void WhiteBalance::adjusterChanged(Adjuster* a, double newval) { int tVal = (int)temp->getValue(); @@ -456,6 +477,36 @@ void WhiteBalance::adjusterChanged(Adjuster* a, double newval) } } +void WhiteBalance::checkBoxToggled(CheckBox* c, CheckValue newval) +{ + if (!(getEnabled() && listener)) { + return; + } + + if (c == observer10) { + // If camera WB, update the temperature and tint according to observer. + const Gtk::TreeModel::Row row = getActiveMethod(); + unsigned int methodId = findWBEntryId(row[methodColumns.colLabel], WBLT_GUI); + const WBEntry &currMethod = WBParams::getWbEntries()[methodId]; + if (row[methodColumns.colLabel] != M("GENERAL_UNCHANGED") && currMethod.type == WBEntry::Type::CAMERA && wbp) { + double ctemp, cgreen; + wbp->getCamWB(ctemp, cgreen, + observer10->getValue() == CheckValue::off + ? rtengine::StandardObserver::TWO_DEGREES + : rtengine::StandardObserver::TEN_DEGREES); + temp->setValue(temp->getAddMode() ? 0.0 : static_cast(ctemp)); + green->setValue(green->getAddMode() ? 0.0 : cgreen); + } + + listener->panelChanged( + EvWBObserver10, + c->getValue() == CheckValue::on ? M("GENERAL_ENABLED") + : c->getValue() == CheckValue::off + ? M("GENERAL_DISABLED") + : M("GENERAL_UNCHANGED")); + } +} + void WhiteBalance::optChanged () { Gtk::TreeModel::Row row = getActiveMethod(); @@ -472,6 +523,7 @@ void WhiteBalance::optChanged () return; } StudLabel->hide(); + mulLabel->show(); if (opt != row[methodColumns.colId]) { @@ -482,6 +534,7 @@ void WhiteBalance::optChanged () green->setEditedState (UnEdited); equal->setEditedState (UnEdited); tempBias->setEditedState (UnEdited); + observer10->setEdited(false); } else { unsigned int methodId = findWBEntryId (row[methodColumns.colLabel], WBLT_GUI); const WBEntry& currMethod = WBParams::getWbEntries()[methodId]; @@ -498,7 +551,10 @@ void WhiteBalance::optChanged () case WBEntry::Type::CAMERA: if (wbp) { double ctemp, cgreen; - wbp->getCamWB (ctemp, cgreen); + wbp->getCamWB(ctemp, cgreen, + observer10->getValue() == CheckValue::off + ? rtengine::StandardObserver::TWO_DEGREES + : rtengine::StandardObserver::TEN_DEGREES); temp->setValue (temp->getAddMode() ? 0.0 : (int)ctemp); green->setValue (green->getAddMode() ? 0.0 : cgreen); equal->setValue (equal->getAddMode() ? 0.0 : 1.0); @@ -507,6 +563,7 @@ void WhiteBalance::optChanged () temp->setEditedState (UnEdited); green->setEditedState (UnEdited); equal->setEditedState (UnEdited); + observer10->setEdited(false); } } @@ -517,7 +574,7 @@ void WhiteBalance::optChanged () if (batchMode) { temp->setEditedState (UnEdited); green->setEditedState (UnEdited); - // equal remain as is + // equal and observer remain as is } // Recomputing AutoWB will happen in improccoordinator.cc @@ -540,6 +597,7 @@ void WhiteBalance::optChanged () temp->setEditedState (Edited); green->setEditedState (Edited); equal->setEditedState (Edited); + observer10->setEdited(true); } break; @@ -563,6 +621,7 @@ void WhiteBalance::optChanged () temp->setEditedState (Edited); green->setEditedState (Edited); equal->setEditedState (Edited); + observer10->setEdited(true); } break; @@ -578,6 +637,7 @@ void WhiteBalance::optChanged () void WhiteBalance::spotPressed () { StudLabel->hide(); + mulLabel->show(); if (wblistener) { wblistener->spotWBRequested (getSize()); @@ -599,6 +659,7 @@ void WhiteBalance::read (const ProcParams* pp, const ParamsEdited* pedited) methconn.block (true); equal->setValue (pp->wb.equal); + observer10->setValue(rtengine::StandardObserver::TEN_DEGREES == pp->wb.observer); tempBias->setValue (pp->wb.tempBias); tempBias->set_sensitive(true); @@ -608,6 +669,7 @@ void WhiteBalance::read (const ProcParams* pp, const ParamsEdited* pedited) green->setEditedState (UnEdited); equal->setEditedState (pedited->wb.equal ? Edited : UnEdited); tempBias->setEditedState (pedited->wb.tempBias ? Edited : UnEdited); + observer10->setEdited(pedited->wb.observer); } if (pedited && !pedited->wb.method) { @@ -648,7 +710,7 @@ void WhiteBalance::read (const ProcParams* pp, const ParamsEdited* pedited) if (wbp) { double ctemp = -1.0; double cgreen = -1.0; - wbp->getCamWB (ctemp, cgreen); + wbp->getCamWB (ctemp, cgreen, pp->wb.observer); if (ctemp != -1.0) { // Set the camera's temperature value, or 0.0 if in ADD mode @@ -720,6 +782,7 @@ void WhiteBalance::read (const ProcParams* pp, const ParamsEdited* pedited) StudLabel->show(); } else { StudLabel->hide(); + mulLabel->show(); } } @@ -744,6 +807,7 @@ void WhiteBalance::write (ProcParams* pp, ParamsEdited* pedited) pedited->wb.green = green->getEditedState (); pedited->wb.equal = equal->getEditedState (); pedited->wb.tempBias = tempBias->getEditedState (); + pedited->wb.observer = observer10->getEdited(); pedited->wb.method = row[methodColumns.colLabel] != M("GENERAL_UNCHANGED"); pedited->wb.enabled = !get_inconsistent(); } @@ -759,6 +823,12 @@ void WhiteBalance::write (ProcParams* pp, ParamsEdited* pedited) pp->wb.temperature = temp->getIntValue (); pp->wb.green = green->getValue (); pp->wb.equal = equal->getValue (); + pp->wb.observer = + observer10->getValue() == CheckValue::on + ? rtengine::StandardObserver::TEN_DEGREES + : observer10->getValue() == CheckValue::off + ? rtengine::StandardObserver::TWO_DEGREES + : pp->wb.observer; pp->wb.tempBias = tempBias->getValue (); } @@ -771,7 +841,7 @@ void WhiteBalance::setDefaults (const ProcParams* defParams, const ParamsEdited* if (wbp && defParams->wb.method == "Camera") { double ctemp; double cgreen; - wbp->getCamWB (ctemp, cgreen); + wbp->getCamWB (ctemp, cgreen, defParams->wb.observer); // FIXME: Seems to be always -1.0, called too early? Broken! if (ctemp != -1.0) { @@ -945,14 +1015,20 @@ inline Gtk::TreeRow WhiteBalance::getActiveMethod () return *(method->get_active()); } -void WhiteBalance::WBChanged(double temperature, double greenVal, float studgood) +void WhiteBalance::WBChanged(double temperature, double greenVal, double rw, double gw, double bw, float studgood) { idle_register.add( - [this, temperature, greenVal, studgood]() -> bool + [this, temperature, greenVal, rw, gw, bw, studgood]() -> bool { disableListener(); temp->setValue(temperature); green->setValue(greenVal); + mulLabel->set_text( + Glib::ustring::compose(M("TP_WBALANCE_MULLABEL"), + Glib::ustring::format(std::fixed, std::setprecision(4), rw), + Glib::ustring::format(std::fixed, std::setprecision(2), gw), + Glib::ustring::format(std::fixed, std::setprecision(4), bw)) + ); StudLabel->set_text( Glib::ustring::compose(M("TP_WBALANCE_STUDLABEL"), Glib::ustring::format(std::fixed, std::setprecision(4), studgood)) diff --git a/rtgui/whitebalance.h b/rtgui/whitebalance.h index f172590c8..56d8b646c 100644 --- a/rtgui/whitebalance.h +++ b/rtgui/whitebalance.h @@ -21,6 +21,7 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "guiutils.h" #include "toolpanel.h" #include "wbprovider.h" @@ -35,7 +36,7 @@ public: virtual void spotWBRequested(int size) = 0; }; -class WhiteBalance final : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::AutoWBListener +class WhiteBalance final : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::AutoWBListener { enum WB_LabelType { @@ -45,6 +46,7 @@ class WhiteBalance final : public ToolParamBlock, public AdjusterListener, publi private: Gtk::Label* StudLabel; + Gtk::Label* mulLabel; protected: class MethodColumns : public Gtk::TreeModel::ColumnRecord @@ -60,6 +62,8 @@ protected: add(colId); } }; + + rtengine::ProcEvent EvWBObserver10; static Glib::RefPtr wbPixbufs[rtengine::toUnderlying(rtengine::procparams::WBEntry::Type::CUSTOM) + 1]; Glib::RefPtr refTreeModel; @@ -71,6 +75,7 @@ protected: Adjuster* green; Adjuster* equal; Adjuster* tempBias; + CheckBox* observer10; Gtk::Button* spotbutton; int opt; @@ -114,6 +119,7 @@ public: void spotPressed (); void spotSizeChanged (); void adjusterChanged(Adjuster* a, double newval) override; + void checkBoxToggled(CheckBox* c, CheckValue newval) override; int getSize (); void setWBProvider (WBProvider* p) { @@ -125,7 +131,7 @@ public: } void setWB (int temp, double green); void resetWB (); - void WBChanged (double temp, double green, float studgood) override; + void WBChanged (double temp, double green, double rw, double gw, double bw, float studgood) override; void setAdjusterBehavior (bool tempadd, bool greenadd, bool equaladd, bool tempbiasadd); void trimValues (rtengine::procparams::ProcParams* pp) override; 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."