diff --git a/AUTHORS.txt b/AUTHORS.txt
index b2d1333d2..9d1309026 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -15,6 +15,7 @@ Development contributors, in last name alphabetical order:
Maciek Dworak
Michael Ezra
Flössie
+ Rüdiger Franke
Jean-Christophe Frisch
Ilias Giarimis
Alberto Griggio
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b7cf35099..6de75e748 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,7 +45,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION
endif()
# Warning for GCC 10, which causes problems #5749:
-if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "10.0")
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "10.1")
message(STATUS "WARNING: gcc ${CMAKE_CXX_COMPILER_VERSION} is known to miscompile RawTherapee when using -ftree-loop-vectorize, forcing the option to be off")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-tree-loop-vectorize")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-tree-loop-vectorize")
diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais
index 52d25d85b..d541234cf 100644
--- a/rtdata/languages/Francais
+++ b/rtdata/languages/Francais
@@ -2653,6 +2653,8 @@ TP_WAVELET_CHR_TOOLTIP;Ajuste le chroma en fonction des "niveaux de contraste" e
TP_WAVELET_CHSL;Curseurs
TP_WAVELET_CHTYPE;Méthode de chrominance
TP_WAVELET_COLORT;Opacité Rouge-Vert
+TP_WAVELET_COMPLEX_TOOLTIP;Standard: l’application dispose du nécessaire pour assurer les opérations courantes, l’interface graphique est simplifiée.\nAvancé: toutes les fonctionnalités sont présentes, certaines nécessitent un apprentissage important
+TP_WAVELET_COMPEXPERT;Avancé
TP_WAVELET_COMPCONT;Contraste
TP_WAVELET_COMPGAMMA;Compression gamma
TP_WAVELET_COMPGAMMA_TOOLTIP;Ajuster le gamma de l'image résiduelle vous permet d'équiilibrer les données de l'histogramme.
diff --git a/rtdata/languages/default b/rtdata/languages/default
index 069c87050..e49372201 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -569,10 +569,10 @@ HISTORY_MSG_314;W - Gamut - Reduce artifacts
HISTORY_MSG_315;W - Residual - Contrast
HISTORY_MSG_316;W - Gamut - Skin tar/prot
HISTORY_MSG_317;W - Gamut - Skin hue
-HISTORY_MSG_318;W - Contrast - Fine levels
-HISTORY_MSG_319;W - Contrast - Fine range
-HISTORY_MSG_320;W - Contrast - Coarse range
-HISTORY_MSG_321;W - Contrast - Coarse levels
+HISTORY_MSG_318;W - Contrast - Finer levels
+HISTORY_MSG_319;W - Contrast - Finer range
+HISTORY_MSG_320;W - Contrast - Coarser range
+HISTORY_MSG_321;W - Contrast - Coarser levels
HISTORY_MSG_322;W - Gamut - Avoid color shift
HISTORY_MSG_323;W - ES - Local contrast
HISTORY_MSG_324;W - Chroma - Pastel
@@ -636,14 +636,14 @@ HISTORY_MSG_381;PRS RLD - Radius
HISTORY_MSG_382;PRS RLD - Amount
HISTORY_MSG_383;PRS RLD - Damping
HISTORY_MSG_384;PRS RLD - Iterations
-HISTORY_MSG_385;W - Residual - Color Balance
+HISTORY_MSG_385;W - Residual - Color balance
HISTORY_MSG_386;W - Residual - CB green high
HISTORY_MSG_387;W - Residual - CB blue high
HISTORY_MSG_388;W - Residual - CB green mid
HISTORY_MSG_389;W - Residual - CB blue mid
HISTORY_MSG_390;W - Residual - CB green low
HISTORY_MSG_391;W - Residual - CB blue low
-HISTORY_MSG_392;W - Residual - Color Balance
+HISTORY_MSG_392;W - Residual - Color balance
HISTORY_MSG_393;DCP - Look table
HISTORY_MSG_394;DCP - Baseline exposure
HISTORY_MSG_395;DCP - Base table
@@ -1199,7 +1199,7 @@ HISTORY_MSG_956;Local - CH Curve
HISTORY_MSG_BLSHAPE;Blur by level
HISTORY_MSG_BLURCWAV;Blur chroma
HISTORY_MSG_BLURWAV;Blur luminance
-HISTORY_MSG_BLUWAV;Attenuation Response
+HISTORY_MSG_BLUWAV;Attenuation response
HISTORY_MSG_CAT02PRESET;Cat02 automatic preset
HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors
HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction
@@ -1216,6 +1216,8 @@ HISTORY_MSG_COLORTONING_LABREGION_POWER;CT - region power
HISTORY_MSG_COLORTONING_LABREGION_SATURATION;CT - Saturation
HISTORY_MSG_COLORTONING_LABREGION_SHOWMASK;CT - region show mask
HISTORY_MSG_COLORTONING_LABREGION_SLOPE;CT - region slope
+HISTORY_MSG_COMPLEX;Wavelet complexity
+HISTORY_MSG_COMPLEXRETI;Retinex complexity
HISTORY_MSG_DEHAZE_DEPTH;Dehaze - Depth
HISTORY_MSG_DEHAZE_ENABLED;Haze Removal
HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only
@@ -1223,7 +1225,7 @@ HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP;Dehaze - Show depth map
HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
-HISTORY_MSG_EDGEFFECT;Edge Attenuation Response
+HISTORY_MSG_EDGEFFECT;Edge Attenuation response
HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
HISTORY_MSG_FILMNEGATIVE_FILMBASE;Film base color
HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values
@@ -1270,10 +1272,10 @@ HISTORY_MSG_RESIZE_ALLOWUPSCALING;Resize - Allow upscaling
HISTORY_MSG_SHARPENING_BLUR;Sharpening - Blur radius
HISTORY_MSG_SHARPENING_CONTRAST;Sharpening - Contrast threshold
HISTORY_MSG_SH_COLORSPACE;S/H - Colorspace
-HISTORY_MSG_SIGMACOL;Chroma Attenuation Response
-HISTORY_MSG_SIGMADIR;Dir Attenuation Response
-HISTORY_MSG_SIGMAFIN;Final contrast Attenuation Response
-HISTORY_MSG_SIGMATON;Toning Attenuation Response
+HISTORY_MSG_SIGMACOL;Chroma Attenuation response
+HISTORY_MSG_SIGMADIR;Dir Attenuation response
+HISTORY_MSG_SIGMAFIN;Final contrast Attenuation response
+HISTORY_MSG_SIGMATON;Toning Attenuation response
HISTORY_MSG_SOFTLIGHT_ENABLED;Soft light
HISTORY_MSG_SOFTLIGHT_STRENGTH;Soft light - Strength
HISTORY_MSG_TEMPOUT;CAM02 automatic temperature
@@ -1292,10 +1294,10 @@ HISTORY_MSG_WAVMERGEC;Merge C
HISTORY_MSG_WAVMERGEL;Merge L
HISTORY_MSG_WAVOFFSET;Offset
HISTORY_MSG_WAVOLDSH;Old algorithm
-HISTORY_MSG_WAVRADIUS;Radius Shadows-Highlight
+HISTORY_MSG_WAVRADIUS;Radius shadows-highlights
HISTORY_MSG_WAVSCALE;Scale
HISTORY_MSG_WAVSHOWMASK;Show wavelet mask
-HISTORY_MSG_WAVSIGMA;Attenuation Response
+HISTORY_MSG_WAVSIGMA;Attenuation response
HISTORY_MSG_WAVSOFTRAD;Soft radius clarity
HISTORY_MSG_WAVSOFTRADEND;Soft radius final
HISTORY_MSG_WAVUSHAMET;Clarity method
@@ -3237,18 +3239,18 @@ TP_WAVELET_6;Level 6
TP_WAVELET_7;Level 7
TP_WAVELET_8;Level 8
TP_WAVELET_9;Level 9
-TP_WAVELET_APPLYTO;Apply To
+TP_WAVELET_APPLYTO;Apply to
TP_WAVELET_AVOID;Avoid color shift
TP_WAVELET_B0;Black
-TP_WAVELET_B1;Grey
+TP_WAVELET_B1;Gray
TP_WAVELET_B2;Residual
TP_WAVELET_BACKGROUND;Background
TP_WAVELET_BACUR;Curve
TP_WAVELET_BALANCE;Contrast balance d/v-h
TP_WAVELET_BALANCE_TOOLTIP;Alters the balance between the wavelet directions: vertical-horizontal and diagonal.\nIf contrast, chroma or residual tone mapping are activated, the effect due to balance is amplified.
-TP_WAVELET_BALCHRO;Chrominance balance
-TP_WAVELET_BALCHROM;Denoise Equalizer Blue-yellow Red-green
+TP_WAVELET_BALANCE_TOOLTIP;Alters the balance between the vertical, horizontal and diagonal wavelet directions: .\nActivating contrast, chroma or residual tone mapping amplifies the effect due to balance
TP_WAVELET_BALCHRO_TOOLTIP;If enabled, the 'Contrast balance' curve or slider also modifies chroma balance.
+TP_WAVELET_BALCHROM;Denoise equalizer blue-yellow red-green
TP_WAVELET_BALLUM;Denoise Equalizer White-Black
TP_WAVELET_BANONE;None
TP_WAVELET_BASLI;Slider
@@ -3256,9 +3258,9 @@ TP_WAVELET_BATYPE;Contrast balance method
TP_WAVELET_BL;Blur levels
TP_WAVELET_BLCURVE;Blur by levels
TP_WAVELET_BLURFRAME;Blur
-TP_WAVELET_BLUWAV;Attenuation Response
-TP_WAVELET_CBENAB;Toning and Color Balance
-TP_WAVELET_CB_TOOLTIP;For strong values product color-toning by combining it or not with levels decomposition 'toning'\nFor low values you can change the white balance of the background (sky, ...) without changing that of the front plane, generally more contrasted
+TP_WAVELET_BLUWAV;Attenuation response
+TP_WAVELET_CBENAB;Toning and Color balance
+TP_WAVELET_CB_TOOLTIP;With high values you can create special effects, similar to those achieved with the Chroma Module, but focused on the residual image\nWith moderate values you can manually correct the white balance
TP_WAVELET_CCURVE;Local contrast
TP_WAVELET_CH1;Whole chroma range
TP_WAVELET_CH2;Saturated/pastel
@@ -3266,7 +3268,7 @@ TP_WAVELET_CH3;Link contrast levels
TP_WAVELET_CHCU;Curve
TP_WAVELET_CHR;Chroma-contrast link strength
TP_WAVELET_CHRO;Saturated/pastel threshold
-TP_WAVELET_CHROFRAME;Denoise Chrominance
+TP_WAVELET_CHROFRAME;Denoise chrominance
TP_WAVELET_CHROMAFRAME;Chroma
TP_WAVELET_CHROMCO;Chrominance Coarse
TP_WAVELET_CHROMFI;Chrominance Fine
@@ -3277,10 +3279,14 @@ TP_WAVELET_CHSL;Sliders
TP_WAVELET_CHTYPE;Chrominance method
TP_WAVELET_CLA;Clarity
TP_WAVELET_CLARI;Sharp-mask and Clarity
-TP_WAVELET_COLORT;Opacity Red-Green
+TP_WAVELET_COLORT;Opacity red-green
TP_WAVELET_COMPCONT;Contrast
TP_WAVELET_COMPGAMMA;Compression gamma
TP_WAVELET_COMPGAMMA_TOOLTIP;Adjusting the gamma of the residual image allows you to equilibrate the data and histogram.
+TP_WAVELET_COMPLEXLAB;Complexity
+TP_WAVELET_COMPLEX_TOOLTIP;Standard: shows a reduced set of tools suitable for most processing operations.\nAdvanced: shows the complete set of tools for advanced processing operations
+TP_WAVELET_COMPNORMAL;Standard
+TP_WAVELET_COMPEXPERT;Advanced
TP_WAVELET_COMPTM;Tone mapping
TP_WAVELET_CONTEDIT;'After' contrast curve
TP_WAVELET_CONTFRAME;Contrast - Compression
@@ -3289,16 +3295,16 @@ TP_WAVELET_CONTRA;Contrast
TP_WAVELET_CONTRASTEDIT;Finer - Coarser levels
TP_WAVELET_CONTRAST_MINUS;Contrast -
TP_WAVELET_CONTRAST_PLUS;Contrast +
-TP_WAVELET_CONTRA_TOOLTIP;Changes contrast of the residual image.
+TP_WAVELET_CONTRA_TOOLTIP;Changes the residual image contrast.
TP_WAVELET_CTYPE;Chrominance control
TP_WAVELET_CURVEEDITOR_BL_TOOLTIP;Disabled if zoom > about 300%
TP_WAVELET_CURVEEDITOR_CC_TOOLTIP;Modifies local contrast as a function of the original local contrast (abscissa).\nLow abscissa values represent small local contrast (real values about 10..20).\n50% abscissa represents average local contrast (real value about 100..300).\n66% abscissa represents standard deviation of local contrast (real value about 300..800).\n100% abscissa represents maximum local contrast (real value about 3000..8000).
TP_WAVELET_CURVEEDITOR_CH;Contrast levels=f(Hue)
TP_WAVELET_CURVEEDITOR_CH_TOOLTIP;Modifies each level's contrast as a function of hue.\nTake care not to overwrite changes made with the Gamut sub-tool's hue controls.\nThe curve will only have an effect when wavelet contrast level sliders are non-zero.
TP_WAVELET_CURVEEDITOR_CL;L
-TP_WAVELET_CURVEEDITOR_CL_TOOLTIP;Applies a final contrast luminance curve at the end of the wavelet treatment.
+TP_WAVELET_CURVEEDITOR_CL_TOOLTIP;Applies a final contrast-luminance curve at the end of the wavelet processing.
TP_WAVELET_CURVEEDITOR_HH;HH
-TP_WAVELET_CURVEEDITOR_HH_TOOLTIP;Modifies the residual image's hue as a function of hue.
+TP_WAVELET_CURVEEDITOR_HH_TOOLTIP;Modifies the residual image hue as a function of hue.
TP_WAVELET_DALL;All directions
TP_WAVELET_DAUB;Edge performance
TP_WAVELET_DAUB2;D2 - low
@@ -3307,34 +3313,34 @@ TP_WAVELET_DAUB6;D6 - standard plus
TP_WAVELET_DAUB10;D10 - medium
TP_WAVELET_DAUB14;D14 - high
TP_WAVELET_DAUBLOCAL;Wavelet Edge performance
-TP_WAVELET_DAUB_TOOLTIP;Changes Daubechies coefficients:\nD4 = Standard,\nD14 = Often best performance, 10% more time-intensive.\n\nAffects edge detection as well as the general quality of the firsts levels. However the quality is not strictly related to this coefficient and can vary with images and uses.
+TP_WAVELET_DAUB_TOOLTIP;Changes Daubechies coefficients:\nD4 = Standard,\nD14 = Often best performance, 10% more time-intensive.\n\nAffects edge detection as well as the general quality of the first levels. However the quality is not strictly related to this coefficient and can vary depending on image and use.
TP_WAVELET_DIRFRAME;Directional contrast
TP_WAVELET_DONE;Vertical
TP_WAVELET_DTHR;Diagonal
TP_WAVELET_DTWO;Horizontal
TP_WAVELET_EDCU;Curve
-TP_WAVELET_EDEFFECT;Attenuation Response
-TP_WAVELET_EDEFFECT_TOOLTIP;This slider controls how wide the range of contrast values are that receive the maximum effect from the tool.\nMaximum value (2.5) disabled the tool
+TP_WAVELET_EDEFFECT;Attenuation response
+TP_WAVELET_EDEFFECT_TOOLTIP;This slider selects the range of contrast values that will receive the full effect of any adjustment
TP_WAVELET_EDGCONT;Local contrast
-TP_WAVELET_EDGCONT_TOOLTIP;Adjusting the points to the left decreases contrast, and to the right increases it.\nBottom-left, top-left, top-right and bottom-right represent respectively local contrast for low values, mean, mean+stdev and maxima.
+TP_WAVELET_EDGCONT_TOOLTIP;Adjusting the points to the left decreases contrast, and to the right increases it.\nBottom-left, top-left, top-right and bottom-right represent respectively local contrast for low values, mean, mean+std. dev. and maxima.
TP_WAVELET_EDGE;Edge Sharpness
TP_WAVELET_EDGEAMPLI;Base amplification
TP_WAVELET_EDGEDETECT;Gradient sensitivity
TP_WAVELET_EDGEDETECTTHR;Threshold low (noise)
-TP_WAVELET_EDGEDETECTTHR2;Threshold high (detection)
-TP_WAVELET_EDGEDETECTTHR_TOOLTIP;This adjuster lets you target edge detection for example to avoid applying edge sharpness to fine details, such as noise in the sky.
+TP_WAVELET_EDGEDETECTTHR2;Edge enhancement
+TP_WAVELET_EDGEDETECTTHR_TOOLTIP;This slider sets a threshold below which finer details won't be considered as an edge
TP_WAVELET_EDGEDETECT_TOOLTIP;Moving the slider to the right increases edge sensitivity. This affects local contrast, edge settings and noise.
TP_WAVELET_EDGESENSI;Edge sensitivity
TP_WAVELET_EDGREINF_TOOLTIP;Reinforce or reduce the action of the first level, do the opposite to the second level, and leave the rest unchanged.
TP_WAVELET_EDGTHRESH;Detail
TP_WAVELET_EDGTHRESH_TOOLTIP;Change the repartition between the first levels and the others. The higher the threshold the more the action is centered on the first levels. Be careful with negative values, they increase the action of high levels and can introduce artifacts.
TP_WAVELET_EDRAD;Radius
-TP_WAVELET_EDRAD_TOOLTIP;This radius adjustment is very different from those in other sharpening tools. Its value is compared to each level through a complex function. In this sense, a value of zero still has an effect.
-TP_WAVELET_EDSL;Threshold Sliders
+TP_WAVELET_EDRAD_TOOLTIP;This adjustment controls the local enhancement. A value of zero still has an effect
+TP_WAVELET_EDSL;Threshold sliders
TP_WAVELET_EDTYPE;Local contrast method
TP_WAVELET_EDVAL;Strength
TP_WAVELET_FINAL;Final Touchup
-TP_WAVELET_FINCFRAME;Final Local Contrast
+TP_WAVELET_FINCFRAME;Final local contrast
TP_WAVELET_FINCOAR_TOOLTIP;The left (positive) part of the curve acts on the finer levels (increase).\nThe 2 points on the abscissa represent the respective action limits of finer and coarser levels 5 and 6 (default).\nThe right (negative) part of the curve acts on the coarser levels (increase).\nAvoid moving the left part of the curve with negative values. Avoid moving the right part of the curve with positives values
TP_WAVELET_FINEST;Finest
TP_WAVELET_HIGHLIGHT;Finer levels luminance range
@@ -3342,7 +3348,7 @@ TP_WAVELET_HS1;Whole luminance range
TP_WAVELET_HS2;Selective luminance range
TP_WAVELET_HUESKIN;Skin hue
TP_WAVELET_HUESKIN_TOOLTIP;The bottom points set the beginning of the transition zone, and the upper points the end of it, where the effect is at its maximum.\n\nIf you need to move the area significantly, or if there are artifacts, then the white balance is incorrect.
-TP_WAVELET_HUESKY;Sky hue
+TP_WAVELET_HUESKY;Hue range
TP_WAVELET_HUESKY_TOOLTIP;The bottom points set the beginning of the transition zone, and the upper points the end of it, where the effect is at its maximum.\n\nIf you need to move the area significantly, or if there are artifacts, then the white balance is incorrect.
TP_WAVELET_ITER;Delta balance levels
TP_WAVELET_ITER_TOOLTIP;Left: increase low levels and reduce high levels,\nRight: reduce low levels and increase high levels.
@@ -3350,18 +3356,18 @@ TP_WAVELET_LABEL;Wavelet Levels
TP_WAVELET_LARGEST;Coarsest
TP_WAVELET_LEVCH;Chroma
TP_WAVELET_LEVDIR_ALL;All levels, in all directions
-TP_WAVELET_LEVDIR_INF;Finer details levels, with selected level
+TP_WAVELET_LEVDIR_INF;Finer detail levels, including selected level
TP_WAVELET_LEVDIR_ONE;One level
-TP_WAVELET_LEVDIR_SUP;Coarser details levels, without selected level
+TP_WAVELET_LEVDIR_SUP;Coarser detail levels, excluding selected level
TP_WAVELET_LEVELS;Wavelet levels
-TP_WAVELET_LEVELS_TOOLTIP;Choose the number of detail levels the image is to be decomposed into. More levels require more RAM and require a longer processing time.
+TP_WAVELET_LEVELS_TOOLTIP;Choose the number of wavelet decomposition levels for the image.\nMore levels require more RAM and require a longer processing time.
TP_WAVELET_LEVF;Contrast
TP_WAVELET_LEVLABEL;Preview maximum possible levels = %1
TP_WAVELET_LEVONE;Level 2
TP_WAVELET_LEVTHRE;Level 4
TP_WAVELET_LEVTWO;Level 3
TP_WAVELET_LEVZERO;Level 1
-TP_WAVELET_LINKEDG;Link with Edge Sharpness' Strength
+TP_WAVELET_LINKEDG;Link to Edge Sharpness Strength
TP_WAVELET_LIPST;Enhanced algoritm
TP_WAVELET_LOWLIGHT;Coarser levels luminance range
TP_WAVELET_LOWTHR_TOOLTIP;Prevents amplification of fine textures and noise
@@ -3369,7 +3375,7 @@ TP_WAVELET_MEDGREINF;First level
TP_WAVELET_MEDI;Reduce artifacts in blue sky
TP_WAVELET_MEDILEV;Edge detection
TP_WAVELET_MEDILEV_TOOLTIP;When you enable Edge Detection, it is recommanded:\n- to disabled low contrast levels to avoid artifacts,\n- to use high values of gradient sensitivity.\n\nYou can modulate the strength with 'refine' from Denoise and Refine.
-TP_WAVELET_MERGEC;Merge Chroma
+TP_WAVELET_MERGEC;Merge chroma
TP_WAVELET_MERGEL;Merge Luma
TP_WAVELET_NEUTRAL;Neutral
TP_WAVELET_NOIS;Denoise
@@ -3380,24 +3386,24 @@ TP_WAVELET_NPLOW;Low
TP_WAVELET_NPNONE;None
TP_WAVELET_NPTYPE;Neighboring pixels
TP_WAVELET_NPTYPE_TOOLTIP;This algorithm uses the proximity of a pixel and eight of its neighbors. If less difference, edges are reinforced.
-TP_WAVELET_OFFSET_TOOLTIP;Offset modifies the balance between shadows and highlights.\nHigh values here will amplify the contrast change of the highlights, whereas low values will amplify the contrast change of the shadows.\nAlong with a low Attenuation Response value you will able to select the contrasts that will be enhanced.
+TP_WAVELET_OFFSET_TOOLTIP;Offset modifies the balance between low contrast and high contrast details.\nHigh values will amplify contrast changes to the higher contrast details, whereas low values will amplify contrast changes to low contrast details.\nBy using a low Attenuation response value you can select which contrast values will be enhanced.
TP_WAVELET_OLDSH;Algorithm using negatives values
-TP_WAVELET_OPACITY;Opacity Blue-Yellow
+TP_WAVELET_OPACITY;Opacity blue-yellow
TP_WAVELET_OPACITYW;Contrast balance d/v-h curve
TP_WAVELET_OPACITYWL;Local contrast
TP_WAVELET_OPACITYWL_TOOLTIP;Modify the final local contrast at the end of the wavelet treatment.\n\nThe left side represents the smallest local contrast, progressing to the largest local contrast on the right.
TP_WAVELET_PASTEL;Pastel chroma
TP_WAVELET_PROC;Process
TP_WAVELET_PROTAB;Protection
-TP_WAVELET_RADIUS;Radius Shadows - Highlight
+TP_WAVELET_RADIUS;Radius shadows - highlight
TP_WAVELET_RANGEAB;Range a and b %
TP_WAVELET_RE1;Reinforced
TP_WAVELET_RE2;Unchanged
TP_WAVELET_RE3;Reduced
-TP_WAVELET_RESBLUR;Blur Luminance
-TP_WAVELET_RESBLURC;Blur Chroma
+TP_WAVELET_RESBLUR;Blur luminance
+TP_WAVELET_RESBLURC;Blur chroma
TP_WAVELET_RESBLUR_TOOLTIP;Disabled if zoom > about 500%
-TP_WAVELET_RESCHRO;Intensity
+TP_WAVELET_RESCHRO;Strength
TP_WAVELET_RESCON;Shadows
TP_WAVELET_RESCONH;Highlights
TP_WAVELET_RESID;Residual Image
@@ -3406,15 +3412,15 @@ TP_WAVELET_SETTINGS;Wavelet Settings
TP_WAVELET_SHA;Sharp mask
TP_WAVELET_SHFRAME;Shadows/Highlights
TP_WAVELET_SHOWMASK;Show wavelet 'mask'
-TP_WAVELET_SIGMA;Attenuation Response
-TP_WAVELET_SIGMAFIN;Attenuation Response
+TP_WAVELET_SIGMA;Attenuation response
+TP_WAVELET_SIGMAFIN;Attenuation response
TP_WAVELET_SIGMA_TOOLTIP;The effect of the contrast sliders is stronger in medium contrast details, and weaker in high and low contrast details.\n With this slider you can control how quickly the effect dampens towards the extreme contrasts.\n The higher the slider is set, the wider the range of contrasts which will get a strong change, and the higher the risk to generate artifacts.\n .The lower it is, the more the effect will be pinpointed towards a narrow range of contrast values
TP_WAVELET_SKIN;Skin targetting/protection
TP_WAVELET_SKIN_TOOLTIP;At -100 skin-tones are targetted.\nAt 0 all tones are treated equally.\nAt +100 skin-tones are protected while all other tones are affected.
-TP_WAVELET_SKY;Sky targetting/protection
-TP_WAVELET_SKY_TOOLTIP;At -100 sky-tones are targetted.\nAt 0 all tones are treated equally.\nAt +100 sky-tones are protected while all other tones are affected.
-TP_WAVELET_SOFTRAD;Soft Radius
-TP_WAVELET_STREN;Strength
+TP_WAVELET_SKY;Hue targetting/protection
+TP_WAVELET_SKY_TOOLTIP;Allows you to target or protect a range of hues.\nAt -100 selected hues are targetted.\nAt 0 all hues are treated equally.\nAt +100 selected hues are protected while all other hues are targetted.
+TP_WAVELET_SOFTRAD;Soft radius
+TP_WAVELET_STREN;Refine
TP_WAVELET_STRENGTH;Strength
TP_WAVELET_SUPE;Extra
TP_WAVELET_THR;Shadows threshold
@@ -3422,7 +3428,7 @@ TP_WAVELET_THRESHOLD;Finer levels
TP_WAVELET_THRESHOLD2;Coarser levels
TP_WAVELET_THRESHOLD2_TOOLTIP;Only levels from the chosen value to the selected number of ‘wavelet levels’ will be affected by the Shadow luminance range.
TP_WAVELET_THRESHOLD_TOOLTIP;Only levels below and including the chosen value will be affected by the Highlight luminance range.
-TP_WAVELET_THRESWAV;Balance Threshold
+TP_WAVELET_THRESWAV;Balance threshold
TP_WAVELET_THRH;Highlights threshold
TP_WAVELET_TILESBIG;Tiles
TP_WAVELET_TILESFULL;Full image
@@ -3435,11 +3441,11 @@ TP_WAVELET_TMSTRENGTH;Compression strength
TP_WAVELET_TMSTRENGTH_TOOLTIP;Control the strength of tone mapping or contrast compression of the residual image.
TP_WAVELET_TMTYPE;Compression method
TP_WAVELET_TON;Toning
-TP_WAVELET_TONFRAME;Excluded Colors
+TP_WAVELET_TONFRAME;Excluded colors
TP_WAVELET_USH;None
TP_WAVELET_USHARP;Clarity method
TP_WAVELET_USHARP_TOOLTIP;Origin : the source file is the file before Wavelet.\nWavelet : the source file is the file including wavelet threatment
-TP_WAVELET_USH_TOOLTIP;If you select Sharp-mask, wavelet settings will be automatically positioned :\nBackground=black, Process=below, level=3...you can change level between 1 and 4.\n\nIf you select Clarity, wavelet settings will be automatically positioned :\nBackground=residual, Process=above, level=7..you can change level between 5 and 10 and wavelet levels.
+TP_WAVELET_USH_TOOLTIP;If you select Sharp-mask, you can choose any level (in Settings) from 1 to 4 for processing.\nIf you select Clarity, you can choose any level (in Settings) between 5 and Extra.
TP_WAVELET_WAVLOWTHR;Low contrast threshold
TP_WAVELET_WAVOFFSET;Offset
TP_WBALANCE_AUTO;Auto
diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc
index fa9788af0..c17826623 100644
--- a/rtengine/CA_correct_RT.cc
+++ b/rtengine/CA_correct_RT.cc
@@ -123,7 +123,7 @@ float* RawImageSource::CA_correct_RT(
double cared,
double cablue,
bool avoidColourshift,
- const array2D &rawData,
+ array2D &rawData,
double* fitParamsTransfer,
bool fitParamsIn,
bool fitParamsOut,
@@ -1291,7 +1291,7 @@ float* RawImageSource::CA_correct_RT(
for (int i = 0; i < H - 2 * cb; ++i) {
const int firstCol = fc(cfa, i, 0) & 1;
const int colour = fc(cfa, i, firstCol);
- const array2D* nonGreen = colour == 0 ? redFactor : blueFactor;
+ array2D* nonGreen = colour == 0 ? redFactor : blueFactor;
int j = firstCol;
#ifdef __SSE2__
for (; j < W - 7 - 2 * cb; j += 8) {
@@ -1325,7 +1325,7 @@ float* RawImageSource::CA_correct_RT(
const int ngRow = 1 - (fc(cfa, 0, 0) & 1);
const int ngCol = fc(cfa, ngRow, 0) & 1;
const int colour = fc(cfa, ngRow, ngCol);
- const array2D* nonGreen = colour == 0 ? redFactor : blueFactor;
+ array2D* nonGreen = colour == 0 ? redFactor : blueFactor;
for (int i = 0; i < (H + 1 - 2 * cb) / 2; ++i) {
(*nonGreen)[i][(W - 2 * cb + 1) / 2 - 1] = (*nonGreen)[i][(W - 2* cb + 1) / 2 - 2];
}
diff --git a/rtengine/array2D.h b/rtengine/array2D.h
index de6381aeb..512f7bcc1 100644
--- a/rtengine/array2D.h
+++ b/rtengine/array2D.h
@@ -27,7 +27,7 @@
*
* creates an array which is valid within the normal C/C++ scope "{ ... }"
*
- * access to elements is a simple as:
+ * access to elements is as simple as:
*
* array2D my_array (10,10); // creates 10x10 array of floats
* value = my_array[3][5];
@@ -48,25 +48,20 @@
* array2D my_array ; // empty container.
* my_array(10,10) ; // resize to 10x10 array
* my_array(10,10,ARRAY2D_CLEAR_DATA) ; // resize to 10x10 and clear data
- * my_array(10,10,ARRAY2D_CLEAR_DATA|ARRAY2D_LOCK_DATA) ; same but set a lock on changes
*
- * !! locked arrays cannot be resized and cannot be unlocked again !!
*/
#pragma once
-#include // for raise()
#include
+#include
+#include
+#include
+#include "noncopyable.h"
// flags for use
-#define ARRAY2D_LOCK_DATA 1
-#define ARRAY2D_CLEAR_DATA 2
-#define ARRAY2D_BYREFERENCE 4
-#define ARRAY2D_VERBOSE 8
+constexpr unsigned int ARRAY2D_CLEAR_DATA = 1;
+constexpr unsigned int ARRAY2D_BYREFERENCE = 2;
-#include
-#include
-
-#include "noncopyable.h"
template
class array2D :
@@ -74,249 +69,158 @@ class array2D :
{
private:
- int x, y, owner;
- unsigned int flags;
- T ** ptr;
- T * data;
- bool lock; // useful lock to ensure data is not changed anymore.
- void ar_realloc(int w, int h, int offset = 0)
+ ssize_t width;
+ std::vector rows;
+ std::vector buffer;
+
+ void initRows(ssize_t h, int offset = 0)
{
- if ((ptr) && ((h > y) || (4 * h < y))) {
- delete[] ptr;
- ptr = nullptr;
+ rows.resize(h);
+ T* start = buffer.data() + offset;
+ for (ssize_t i = 0; i < h; ++i) {
+ rows[i] = start + width * i;
}
+ }
- if ((data) && (((h * w) > (x * y)) || ((h * w) < ((x * y) / 4)))) {
- delete[] data;
- data = nullptr;
- }
-
- if (ptr == nullptr) {
- ptr = new T*[h];
- }
-
- if (data == nullptr) {
- data = new T[h * w + offset];
- }
-
- x = w;
- y = h;
-
- for (int i = 0; i < h; i++) {
- ptr[i] = data + offset + w * i;
- }
-
- owner = 1;
+ void ar_realloc(ssize_t w, ssize_t h, int offset = 0)
+ {
+ width = w;
+ buffer.resize(h * width + offset);
+ initRows(h, offset);
}
public:
// use as empty declaration, resize before use!
// very useful as a member object
- array2D() :
- x(0), y(0), owner(0), flags(0), ptr(nullptr), data(nullptr), lock(false)
- {
- //printf("got empty array2D init\n");
- }
+ array2D() : width(0) {}
// creator type1
- array2D(int w, int h, unsigned int flgs = 0)
+ array2D(int w, int h, unsigned int flags = 0) : width(w)
{
- flags = flgs;
- lock = flags & ARRAY2D_LOCK_DATA;
- data = new T[h * w];
- owner = 1;
- x = w;
- y = h;
- ptr = new T*[h];
-
- for (int i = 0; i < h; i++) {
- ptr[i] = data + i * w;
- }
-
if (flags & ARRAY2D_CLEAR_DATA) {
- memset(data, 0, w * h * sizeof(T));
+ buffer.resize(h * width, 0);
+ } else {
+ buffer.resize(h * width);
}
+ initRows(h);
}
// creator type 2
- array2D(int w, int h, T ** source, unsigned int flgs = 0)
+ array2D(int w, int h, T ** source, unsigned int flags = 0) : width(w)
{
- flags = flgs;
- //if (lock) { printf("array2D attempt to overwrite data\n");raise(SIGSEGV);}
- lock = flags & ARRAY2D_LOCK_DATA;
- // when by reference
- // TODO: improve this code with ar_realloc()
- owner = (flags & ARRAY2D_BYREFERENCE) ? 0 : 1;
-
- if (owner) {
- data = new T[h * w];
- } else {
- data = nullptr;
- }
-
- x = w;
- y = h;
- ptr = new T*[h];
-
- for (int i = 0; i < h; i++) {
- if (owner) {
- ptr[i] = data + i * w;
-
- for (int j = 0; j < w; j++) {
- ptr[i][j] = source[i][j];
+ rows.resize(h);
+ if (!(flags & ARRAY2D_BYREFERENCE)) {
+ buffer.resize(h * width);
+ T* start = buffer.data();
+ for (ssize_t i = 0; i < h; ++i) {
+ rows[i] = start + i * width;
+ for (ssize_t j = 0; j < width; ++j) {
+ rows[i][j] = source[i][j];
}
- } else {
- ptr[i] = source[i];
}
- }
- }
-
- // destructor
- ~array2D()
- {
-
- if (flags & ARRAY2D_VERBOSE) {
- printf(" deleting array2D size %dx%d \n", x, y);
- }
-
- if ((owner) && (data)) {
- delete[] data;
- }
-
- if (ptr) {
- delete[] ptr;
+ } else {
+ for (ssize_t i = 0; i < h; ++i) {
+ rows[i] = source[i];
+ }
}
}
void fill(const T val, bool multiThread = false)
{
+ const ssize_t height = rows.size();
#ifdef _OPENMP
#pragma omp parallel for if(multiThread)
#endif
- for (int i = 0; i < x * y; ++i) {
- data[i] = val;
+ for (ssize_t i = 0; i < width * height; ++i) {
+ buffer[i] = val;
}
}
void free()
{
- if ((owner) && (data)) {
- delete[] data;
- data = nullptr;
- }
-
- if (ptr) {
- delete [] ptr;
- ptr = nullptr;
- }
+ buffer.clear();
+ rows.clear();
}
// use with indices
- T * operator[](int index) const
+ T * operator[](int index)
{
- assert((index >= 0) && (index < y));
- return ptr[index];
+ assert((index >= 0) && (index < rows.size()));
+ return rows[index];
+ }
+
+ const T * operator[](int index) const
+ {
+ assert((index >= 0) && (index < rows.size()));
+ return rows[index];
}
// use as pointer to T**
operator T**()
{
- return ptr;
+ return rows.data();
}
// use as pointer to T**
- operator const T* const *()
+ operator const T* const *() const
{
- return ptr;
+ return rows.data();
}
- // use as pointer to data
+ // use as pointer to buffer
operator T*()
{
// only if owner this will return a valid pointer
- return data;
+ return buffer.data();
+ }
+
+ operator const T*() const
+ {
+ // only if owner this will return a valid pointer
+ return buffer.data();
}
// useful within init of parent object
// or use as resize of 2D array
- void operator()(int w, int h, unsigned int flgs = 0, int offset = 0)
+ void operator()(int w, int h, unsigned int flags = 0, int offset = 0)
{
- flags = flgs;
-
- if (flags & ARRAY2D_VERBOSE) {
- printf("got init request %dx%d flags=%u\n", w, h, flags);
- printf("previous was data %p ptr %p \n", data, ptr);
- }
-
- if (lock) { // our object was locked so don't allow a change.
- printf("got init request but object was locked!\n");
- raise( SIGSEGV);
- }
-
- lock = flags & ARRAY2D_LOCK_DATA;
-
ar_realloc(w, h, offset);
if (flags & ARRAY2D_CLEAR_DATA) {
- memset(data + offset, 0, static_cast(w) * h * sizeof(T));
+ fill(0);
}
}
- // import from flat data
- void operator()(int w, int h, T* copy, unsigned int flgs = 0)
+ int getWidth() const
{
- flags = flgs;
-
- if (flags & ARRAY2D_VERBOSE) {
- printf("got init request %dx%d flags=%u\n", w, h, flags);
- printf("previous was data %p ptr %p \n", data, ptr);
- }
-
- if (lock) { // our object was locked so don't allow a change.
- printf("got init request but object was locked!\n");
- raise( SIGSEGV);
- }
-
- lock = flags & ARRAY2D_LOCK_DATA;
-
- ar_realloc(w, h);
- memcpy(data, copy, w * h * sizeof(T));
+ return width;
}
- int width() const
+ int getHeight() const
{
- return x;
- }
- int height() const
- {
- return y;
+ return rows.size();
}
operator bool()
{
- return (x > 0 && y > 0);
+ return (width > 0 && !rows.empty());
}
};
template
-class multi_array2D
+class multi_array2D : public rtengine::NonCopyable
{
private:
array2D list[num];
public:
- multi_array2D(int x, int y, int flags = 0, int offset = 0)
+ multi_array2D(int width, int height, int flags = 0, int offset = 0)
{
- for (size_t i = 0; i < num; i++) {
- list[i](x, y, flags, (i + 1) * offset);
+ for (size_t i = 0; i < num; ++i) {
+ list[i](width, height, flags, (i + 1) * offset);
}
}
- ~multi_array2D()
- {
- //printf("trying to delete the list of array2D objects\n");
- }
-
array2D & operator[](int index)
{
assert(static_cast(index) < num);
diff --git a/rtengine/camconst.json b/rtengine/camconst.json
index de06f670f..578ff1811 100644
--- a/rtengine/camconst.json
+++ b/rtengine/camconst.json
@@ -1401,9 +1401,17 @@ Camera constants:
"ranges": { "white": [ 16105, 16270, 16082 ] } // These values are the lowest pixel values >16000 for all ISOs. LENR has a negligble effect.
// No aperture scaling data provided, but likely negligible
},
-
- { // Quality C, only raw crop
- "make_model": [ "FUJIFILM X-T3", "FUJIFILM X-T30", "FUJIFILM X-PRO3", "FUJIFILM X100V", "FUJIFILM X-T4" ],
+
+ { // Quality A, samples provided by Daniel Catalina (#5839) and pi99y (#5860)
+ "make_model": [ "FUJIFILM X-T3", "FUJIFILM X-PRO3" ],
+ "dcraw_matrix": [ 13426,-6334,-1177,-4244,12136,2371,-580,1303,5980 ], // DNG_v11, standard_v2 d65
+ "raw_crop": [ 0, 5, 6252, 4176],
+ "white": [ 16170, 16275, 16170 ] // typical safe-margins with LENR
+ // negligible aperture scaling effect
+ },
+
+ { // Quality B
+ "make_model": [ "FUJIFILM X-T30", "FUJIFILM X100V", "FUJIFILM X-T4" ],
"dcraw_matrix": [ 13426,-6334,-1177,-4244,12136,2371,-580,1303,5980 ], // DNG_v11, standard_v2 d65
"raw_crop": [ 0, 5, 6252, 4176]
},
@@ -2747,6 +2755,12 @@ Camera constants:
"ranges": { "black": 0, "white": 64400 }
},
+ { // Quality B
+ "make_model": ["HASSELBLAD NEX-7", "SONY NEX-7"], // Hasselblad NEX-7 also known as Hasselblad Lunar
+ "dcraw_matrix": [ 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 ], // adobe DNGv12.2 d65
+ "ranges": { "black": 512, "white": 16372 } // Typical white level (samples provided by @ggc on Pixls, influence from LENR unknown
+ },
+
{ // Quality A for tested CFV, the other models have the same sensor (16 megapixel square sensor)
"make_model": [ "Hasselblad V96C", "Hasselblad CFV", "Hasselblad CFV-II" ],
"dcraw_matrix": [ 8519, -3260, -280, -5081, 13459, 1738, -1449, 2960, 7809 ] // borrowed from Adobe's DNG converter
diff --git a/rtengine/color.cc b/rtengine/color.cc
index 61009c81f..5761733f0 100644
--- a/rtengine/color.cc
+++ b/rtengine/color.cc
@@ -1772,7 +1772,7 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b,
}
}
-void Color::RGB2L(float *R, float *G, float *B, float *L, const float wp[3][3], int width)
+void Color::RGB2L(const float *R, const float *G, const float *B, float *L, const float wp[3][3], int width)
{
#ifdef __SSE2__
diff --git a/rtengine/color.h b/rtengine/color.h
index 76edae6a1..704871d39 100644
--- a/rtengine/color.h
+++ b/rtengine/color.h
@@ -623,7 +623,7 @@ public:
static void XYZ2Lab(float x, float y, float z, float &L, float &a, float &b);
static void RGB2Lab(float *X, float *Y, float *Z, float *L, float *a, float *b, const float wp[3][3], int width);
static void Lab2RGBLimit(float *L, float *a, float *b, float *R, float *G, float *B, const float wp[3][3], float limit, float afactor, float bfactor, int width);
- static void RGB2L(float *X, float *Y, float *Z, float *L, const float wp[3][3], int width);
+ static void RGB2L(const float *R, const float *G, const float *B, float *L, const float wp[3][3], int width);
/**
* @brief Convert Lab in Yuv
diff --git a/rtengine/guidedfilter.cc b/rtengine/guidedfilter.cc
index b3f843bc1..3f5e00e05 100644
--- a/rtengine/guidedfilter.cc
+++ b/rtengine/guidedfilter.cc
@@ -82,8 +82,8 @@ int calculate_subsampling(int w, int h, int r)
void guidedFilter(const array2D &guide, const array2D &src, array2D &dst, int r, float epsilon, bool multithread, int subsampling)
{
- const int W = src.width();
- const int H = src.height();
+ const int W = src.getWidth();
+ const int H = src.getHeight();
if (subsampling <= 0) {
subsampling = calculate_subsampling(W, H, r);
@@ -94,8 +94,8 @@ void guidedFilter(const array2D &guide, const array2D &src, array2
const auto apply =
[=](Op op, array2D &res, const array2D &a, const array2D &b, const array2D &c=array2D()) -> void
{
- const int w = res.width();
- const int h = res.height();
+ const int w = res.getWidth();
+ const int h = res.getHeight();
#ifdef _OPENMP
#pragma omp parallel for if (multithread)
@@ -142,12 +142,12 @@ void guidedFilter(const array2D &guide, const array2D &src, array2
const auto f_subsample =
[=](array2D &d, const array2D &s) -> void
{
- if (d.width() == s.width() && d.height() == s.height()) {
+ if (d.getWidth() == s.getWidth() && d.getHeight() == s.getHeight()) {
#ifdef _OPENMP
# pragma omp parallel for if (multithread)
#endif
- for (int y = 0; y < s.height(); ++y) {
- for (int x = 0; x < s.width(); ++x) {
+ for (int y = 0; y < s.getHeight(); ++y) {
+ for (int x = 0; x < s.getWidth(); ++x) {
d[y][x] = s[y][x];
}
}
@@ -164,9 +164,9 @@ void guidedFilter(const array2D &guide, const array2D &src, array2
const auto f_mean =
[multithread](array2D &d, array2D &s, int rad) -> void
{
- rad = LIM(rad, 0, (min(s.width(), s.height()) - 1) / 2 - 1);
- // boxblur(s, d, rad, s.width(), s.height(), multithread);
- boxblur(static_cast(s), static_cast(d), rad, s.width(), s.height(), multithread);
+ rad = LIM(rad, 0, (min(s.getWidth(), s.getHeight()) - 1) / 2 - 1);
+ // boxblur(s, d, rad, s.getWidth(), s.getHeight(), multithread);
+ boxblur(static_cast(s), static_cast(d), rad, s.getWidth(), s.getHeight(), multithread);
};
array2D I1(w, h);
@@ -225,10 +225,10 @@ void guidedFilter(const array2D &guide, const array2D &src, array2
DEBUG_DUMP(meanb);
// speedup by heckflosse67
- const int Ws = meana.width();
- const int Hs = meana.height();
- const int Wd = q.width();
- const int Hd = q.height();
+ const int Ws = meana.getWidth();
+ const int Hs = meana.getHeight();
+ const int Wd = q.getWidth();
+ const int Hd = q.getHeight();
const float col_scale = float(Ws) / float(Wd);
const float row_scale = float(Hs) / float(Hd);
@@ -249,8 +249,8 @@ void guidedFilterLog(const array2D &guide, float base, array2D &ch
#ifdef _OPENMP
# pragma omp parallel for if (multithread)
#endif
- for (int y = 0; y < chan.height(); ++y) {
- for (int x = 0; x < chan.width(); ++x) {
+ for (int y = 0; y < chan.getHeight(); ++y) {
+ for (int x = 0; x < chan.getWidth(); ++x) {
chan[y][x] = xlin2log(max(chan[y][x], 0.f), base);
}
}
@@ -260,8 +260,8 @@ void guidedFilterLog(const array2D &guide, float base, array2D &ch
#ifdef _OPENMP
# pragma omp parallel for if (multithread)
#endif
- for (int y = 0; y < chan.height(); ++y) {
- for (int x = 0; x < chan.width(); ++x) {
+ for (int y = 0; y < chan.getHeight(); ++y) {
+ for (int x = 0; x < chan.getWidth(); ++x) {
chan[y][x] = xlog2lin(max(chan[y][x], 0.f), base);
}
}
diff --git a/rtengine/ipdehaze.cc b/rtengine/ipdehaze.cc
index 7d715a9b0..6526d0d1e 100644
--- a/rtengine/ipdehaze.cc
+++ b/rtengine/ipdehaze.cc
@@ -103,10 +103,10 @@ void restore(Imagefloat *rgb, float maxval, bool multithread)
}
}
-int get_dark_channel(const array2D &R, const array2D &G, const array2D &B, const array2D &dst, int patchsize, const float ambient[3], bool clip, bool multithread, float strength)
+int get_dark_channel(const array2D &R, const array2D &G, const array2D &B, array2D &dst, int patchsize, const float ambient[3], bool clip, bool multithread, float strength)
{
- const int W = R.width();
- const int H = R.height();
+ const int W = R.getWidth();
+ const int H = R.getHeight();
#ifdef _OPENMP
#pragma omp parallel for if (multithread)
@@ -162,10 +162,10 @@ int get_dark_channel(const array2D &R, const array2D &G, const arr
return (W / patchsize + ((W % patchsize) > 0)) * (H / patchsize + ((H % patchsize) > 0));
}
-int get_dark_channel_downsized(const array2D &R, const array2D &G, const array2D &B, const array2D &dst, int patchsize, bool multithread)
+int get_dark_channel_downsized(const array2D &R, const array2D &G, const array2D &B, array2D &dst, int patchsize, bool multithread)
{
- const int W = R.width();
- const int H = R.height();
+ const int W = R.getWidth();
+ const int H = R.getHeight();
#ifdef _OPENMP
#pragma omp parallel for if (multithread)
@@ -195,8 +195,8 @@ int get_dark_channel_downsized(const array2D &R, const array2D &G,
float estimate_ambient_light(const array2D &R, const array2D &G, const array2D &B, const array2D &dark, int patchsize, int npatches, float ambient[3])
{
- const int W = R.width();
- const int H = R.height();
+ const int W = R.getWidth();
+ const int H = R.getHeight();
float darklim = RT_INFINITY_F;
{
diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc
index b349a454a..2c86db032 100644
--- a/rtengine/iplocallab.cc
+++ b/rtengine/iplocallab.cc
@@ -1840,8 +1840,8 @@ void tone_eq(array2D &R, array2D &G, array2D &B, const stru
{
BENCHFUN
- const int W = R.width();
- const int H = R.height();
+ const int W = R.getWidth();
+ const int H = R.getHeight();
array2D Y(W, H);
const auto log2 =
diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc
index 9b9a9612e..c2798af77 100644
--- a/rtengine/ipwavelet.cc
+++ b/rtengine/ipwavelet.cc
@@ -323,14 +323,14 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const
}
cp.CHSLmet = 1;
- cp.EDmet = 1;
-
+ cp.EDmet = 2;
+/*
if (params->wavelet.EDmethod == "SL") {
cp.EDmet = 1;
} else if (params->wavelet.EDmethod == "CU") {
cp.EDmet = 2;
}
-
+*/
cp.cbena = params->wavelet.cbenab;
cp.blhigh = (float)params->wavelet.bluehigh;
cp.grhigh = (float)params->wavelet.greenhigh;
@@ -1579,10 +1579,16 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const
if (numtiles > 1) {
float factor = Vmask[i1] * Hmask[j1];
+ if(L <= 0.f) {
+ L= 1.f;
+ }
dsttmp->L[i][j] += factor * L;
dsttmp->a[i][j] += factor * a;
dsttmp->b[i][j] += factor * b;
} else {
+ if(L <= 0.f) {
+ L= 1.f;
+ }
dsttmp->L[i][j] = L;
dsttmp->a[i][j] = a;
dsttmp->b[i][j] = b;
@@ -2073,7 +2079,8 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float *
ContrastResid(WavCoeffs_L0, cp, W_L, H_L, maxp);
}
- if ((cp.conres >= 0.f || cp.conresH >= 0.f) && cp.resena && !cp.oldsh) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step
+ // if ((cp.conres >= 0.f || cp.conresH >= 0.f) && cp.resena && !cp.oldsh) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step
+ if ((cp.conres >= 0.f || cp.conresH >= 0.f) && cp.resena) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step
const std::unique_ptr temp(new LabImage(W_L, H_L));
#ifdef _OPENMP
#pragma omp parallel for num_threads(wavNestedLevels) if (wavNestedLevels>1)
@@ -2098,7 +2105,8 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float *
}
}
- if ((cp.conres != 0.f || cp.conresH != 0.f) && cp.resena && cp.oldsh) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step
+ // if ((cp.conres != 0.f || cp.conresH != 0.f) && cp.resena && cp.oldsh) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step
+ if ((cp.conres < 0.f || cp.conresH < 0.f) && cp.resena) { // cp.conres = 0.f and cp.comresH = 0.f means that all will be multiplied by 1.f, so we can skip this step
#ifdef _OPENMP
#pragma omp parallel for
#endif
@@ -2208,9 +2216,9 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float *
for (int lvl = 0; lvl < 4; lvl++) {
for (int dir = 1; dir < 4; dir++) {
const float* const* WavCoeffs_LL = WaveletCoeffs_L.level_coeffs(lvl);
- float tempkoeli;
+ float tempkoeli = 0.f;
calckoe (WavCoeffs_LL, gradw, tloww, koeLi, lvl , dir, W_L, H_L, edd, tempkoeli, tmC);
- maxkoeLi[lvl * 3 + dir - 1] = tempkoeli;
+ maxkoeLi[lvl * 3 + dir - 1] = tempkoeli ;
// return convolution KoeLi and maxkoeLi of level 0 1 2 3 and Dir Horiz, Vert, Diag
}
}
@@ -2766,7 +2774,6 @@ void ImProcFunctions::calckoe (const float* const* WavCoeffs_LL, float gradw, fl
if (koeLi[level * 3 + dir - 1][i * W_L + j] > maxkoeLi) {
maxkoeLi = koeLi[level * 3 + dir - 1][i * W_L + j];
}
-
float diff = maxkoeLi - koeLi[level * 3 + dir - 1][i * W_L + j];
diff *= diffFactor;
koeLi[level * 3 + dir - 1][i * W_L + j] = maxkoeLi - diff;
@@ -2781,13 +2788,13 @@ void ImProcFunctions::finalContAllL(float* const* WavCoeffs_L, float * WavCoeffs
if (cp.diagcurv && cp.finena && MaxP[level] > 0.f && mean[level] != 0.f && sigma[level] != 0.f) { //curve
float insigma = 0.666f; //SD
float logmax = log(MaxP[level]); //log Max
- float rapX = (mean[level] + cp.sigmafin * sigma[level]) / MaxP[level]; //rapport between sD / max
+ float rapX = (mean[level] + cp.sigmafin * sigma[level]) / (MaxP[level]); //rapport between sD / max
float inx = log(insigma);
float iny = log(rapX);
float rap = inx / iny; //koef
float asig = 0.166f / (sigma[level] * cp.sigmafin);
float bsig = 0.5f - asig * mean[level];
- float amean = 0.5f / mean[level];
+ float amean = 0.5f / (mean[level]);
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic, W_L * 16) num_threads(wavNestedLevels) if (wavNestedLevels>1)
@@ -3058,7 +3065,6 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float maxkoeLi, bool lipschitz,
koe[i * W_L + j] = rtengine::min(thr2, std::fabs(tmC[i][j] / temp));
maxkoe = rtengine::max(maxkoe, koe[i * W_L + j]);
-
float diff = maxkoe - koe[i * W_L + j];
diff *= (cp.eddet / 100.f);
float interm = maxkoe - diff;
@@ -3089,10 +3095,13 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float maxkoeLi, bool lipschitz,
float atten01234 = 0.80f;
value *= (atten01234 * scaleskip[1]); //for zoom < 100% reduce strength...I choose level 1...but!!
}
-
+ float edghig = settings->edghi;//increase or reduce "reinforce"
+ float edglow = settings->edglo;//increase or reduce "reduce"
+ float limrad = settings->limrad;//threshold action in function radius (rad)
+ printf("edghi=%f edglo=%f limrad=%f\n", edghig, edglow, limrad);
// value *= beta;
float edge = 1.f;
- float lim0 = 20.f; //arbitrary limit for low radius and level between 2 or 3 to 30 maxi
+ float lim0 = limrad; //arbitrary limit for low radius and level between 2 or 3 to 30 maxi
float lev = float (level);
float repart = (float)cp.til;
@@ -3100,15 +3109,14 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float maxkoeLi, bool lipschitz,
if (cp.reinforce != 2) {
const float brepart =
cp.reinforce == 1
- ? 3.f
- : 0.5f;
+ ? edghig
+ : edglow;
const float arepart = -(brepart - 1.f) / (lim0 / 60.f);
- if (rad < lim0 / 60.f) {
+ if (rad < (lim0 / 60.f)) {
repart *= (arepart * rad + brepart); //linear repartition of repart
}
}
-
float al0 = 1.f + (repart) / 50.f;
float al10 = 1.0f; //arbitrary value ==> less = take into account high levels
// float ak =-(al0-al10)/10.f;//10 = maximum levels
@@ -3116,15 +3124,16 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float maxkoeLi, bool lipschitz,
float bk = al0;
float koef = ak * level + bk; //modulate for levels : more levels high, more koef low ==> concentrated action on low levels, without or near for high levels
float expkoef = -std::pow(std::fabs(rad - lev), koef); //reduce effect for high levels
+ printf("repart=%f\n", repart);
if (cp.reinforce == 3) {
- if (rad < lim0 / 60.f && level == 0) {
+ if (rad < (lim0 / 60.f) && level == 0) {
expkoef *= abs(repart); //reduce effect for low values of rad and level=0==> quasi only level 1 is effective
}
}
if (cp.reinforce == 1) {
- if (rad < lim0 / 60.f && level == 1) {
+ if (rad < (lim0 / 60.f) && level == 1) {
expkoef /= repart; //increase effect for low values of rad and level=1==> quasi only level 0 is effective
}
}
@@ -3158,13 +3167,13 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float maxkoeLi, bool lipschitz,
// if (exa) {//curve
float insigma = 0.666f; //SD
float logmax = log(MaxP[level]); //log Max
- float rapX = (mean[level] + sigma[level]) / MaxP[level]; //rapport between sD / max
+ float rapX = (mean[level] + sigma[level]) / (MaxP[level]); //rapport between sD / max
float inx = log(insigma);
float iny = log(rapX);
float rap = inx / iny; //koef
- float asig = 0.166f / sigma[level];
+ float asig = 0.166f / (sigma[level]);
float bsig = 0.5f - asig * mean[level];
- float amean = 0.5f / mean[level];
+ float amean = 0.5f / (mean[level]);
float absciss = 0.f;
float kinterm;
float kmul;
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index 863c7fc79..3d1f3e071 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -459,6 +459,7 @@ RetinexParams::RetinexParams() :
shadows(0),
stonalwidth(80),
radius(40),
+ complexmethod("normal"),
retinexMethod("high"),
retinexcolorspace("Lab"),
gammaretinex("none"),
@@ -496,6 +497,7 @@ bool RetinexParams::operator ==(const RetinexParams& other) const
&& shadows == other.shadows
&& stonalwidth == other.stonalwidth
&& radius == other.radius
+ && complexmethod == other.complexmethod
&& retinexMethod == other.retinexMethod
&& retinexcolorspace == other.retinexcolorspace
&& gammaretinex == other.gammaretinex
@@ -2395,6 +2397,7 @@ WaveletParams::WaveletParams() :
CLmethod("all"),
Backmethod("grey"),
Tilesmethod("full"),
+ complexmethod("normal"),
daubcoeffmethod("4_"),
CHmethod("without"),
Medgreinf("less"),
@@ -2527,6 +2530,7 @@ bool WaveletParams::operator ==(const WaveletParams& other) const
&& CLmethod == other.CLmethod
&& Backmethod == other.Backmethod
&& Tilesmethod == other.Tilesmethod
+ && complexmethod == other.complexmethod
&& daubcoeffmethod == other.daubcoeffmethod
&& CHmethod == other.CHmethod
&& Medgreinf == other.Medgreinf
@@ -5025,6 +5029,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
saveToKeyfile(!pedited || pedited->retinex.limd, "Retinex", "Limd", retinex.limd, keyFile);
saveToKeyfile(!pedited || pedited->retinex.highl, "Retinex", "highl", retinex.highl, keyFile);
saveToKeyfile(!pedited || pedited->retinex.skal, "Retinex", "skal", retinex.skal, keyFile);
+ saveToKeyfile(!pedited || pedited->retinex.complexmethod, "Retinex", "complexMethod", retinex.complexmethod, keyFile);
saveToKeyfile(!pedited || pedited->retinex.retinexMethod, "Retinex", "RetinexMethod", retinex.retinexMethod, keyFile);
saveToKeyfile(!pedited || pedited->retinex.mapMethod, "Retinex", "mapMethod", retinex.mapMethod, keyFile);
saveToKeyfile(!pedited || pedited->retinex.viewMethod, "Retinex", "viewMethod", retinex.viewMethod, keyFile);
@@ -5988,6 +5993,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
saveToKeyfile(!pedited || pedited->wavelet.iter, "Wavelet", "Iter", wavelet.iter, keyFile);
saveToKeyfile(!pedited || pedited->wavelet.thres, "Wavelet", "MaxLev", wavelet.thres, keyFile);
saveToKeyfile(!pedited || pedited->wavelet.Tilesmethod, "Wavelet", "TilesMethod", wavelet.Tilesmethod, keyFile);
+ saveToKeyfile(!pedited || pedited->wavelet.complexmethod, "Wavelet", "complexMethod", wavelet.complexmethod, keyFile);
saveToKeyfile(!pedited || pedited->wavelet.daubcoeffmethod, "Wavelet", "DaubMethod", wavelet.daubcoeffmethod, keyFile);
saveToKeyfile(!pedited || pedited->wavelet.CLmethod, "Wavelet", "ChoiceLevMethod", wavelet.CLmethod, keyFile);
saveToKeyfile(!pedited || pedited->wavelet.Backmethod, "Wavelet", "BackMethod", wavelet.Backmethod, keyFile);
@@ -6494,6 +6500,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
if (keyFile.has_group("Retinex")) {
assignFromKeyfile(keyFile, "Retinex", "Median", pedited, retinex.medianmap, pedited->retinex.medianmap);
+ assignFromKeyfile(keyFile, "Retinex", "complexMethod", pedited, retinex.complexmethod, pedited->retinex.complexmethod);
assignFromKeyfile(keyFile, "Retinex", "RetinexMethod", pedited, retinex.retinexMethod, pedited->retinex.retinexMethod);
assignFromKeyfile(keyFile, "Retinex", "mapMethod", pedited, retinex.mapMethod, pedited->retinex.mapMethod);
assignFromKeyfile(keyFile, "Retinex", "viewMethod", pedited, retinex.viewMethod, pedited->retinex.viewMethod);
@@ -7858,6 +7865,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "Wavelet", "ChoiceLevMethod", pedited, wavelet.CLmethod, pedited->wavelet.CLmethod);
assignFromKeyfile(keyFile, "Wavelet", "BackMethod", pedited, wavelet.Backmethod, pedited->wavelet.Backmethod);
assignFromKeyfile(keyFile, "Wavelet", "TilesMethod", pedited, wavelet.Tilesmethod, pedited->wavelet.Tilesmethod);
+ assignFromKeyfile(keyFile, "Wavelet", "complexMethod", pedited, wavelet.complexmethod, pedited->wavelet.complexmethod);
assignFromKeyfile(keyFile, "Wavelet", "DaubMethod", pedited, wavelet.daubcoeffmethod, pedited->wavelet.daubcoeffmethod);
assignFromKeyfile(keyFile, "Wavelet", "CHromaMethod", pedited, wavelet.CHmethod, pedited->wavelet.CHmethod);
assignFromKeyfile(keyFile, "Wavelet", "Medgreinf", pedited, wavelet.Medgreinf, pedited->wavelet.Medgreinf);
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index 7d609494e..0af03eaee 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -336,6 +336,7 @@ struct RetinexParams {
int stonalwidth;
int radius;
+ Glib::ustring complexmethod;
Glib::ustring retinexMethod;
Glib::ustring retinexcolorspace;
Glib::ustring gammaretinex;
@@ -1790,6 +1791,7 @@ struct WaveletParams {
Glib::ustring CLmethod;
Glib::ustring Backmethod;
Glib::ustring Tilesmethod;
+ Glib::ustring complexmethod;
Glib::ustring daubcoeffmethod;
Glib::ustring CHmethod;
Glib::ustring Medgreinf;
diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h
index 3c19efd67..75aac923c 100644
--- a/rtengine/rawimagesource.h
+++ b/rtengine/rawimagesource.h
@@ -247,7 +247,7 @@ protected:
double cared,
double cablue,
bool avoidColourshift,
- const array2D &rawData,
+ array2D &rawData,
double* fitParamsTransfer,
bool fitParamsIn,
bool fitParamsOut,
diff --git a/rtengine/rescale.h b/rtengine/rescale.h
index 2138cd8e8..3126a7c58 100644
--- a/rtengine/rescale.h
+++ b/rtengine/rescale.h
@@ -31,8 +31,8 @@ namespace rtengine
inline float getBilinearValue(const array2D &src, float x, float y)
{
- const int W = src.width();
- const int H = src.height();
+ const int W = src.getWidth();
+ const int H = src.getHeight();
// Get integer and fractional parts of numbers
int xi = x;
@@ -57,10 +57,10 @@ inline float getBilinearValue(const array2D &src, float x, float y)
inline void rescaleBilinear(const array2D &src, array2D &dst, bool multithread)
{
- const int Ws = src.width();
- const int Hs = src.height();
- const int Wd = dst.width();
- const int Hd = dst.height();
+ const int Ws = src.getWidth();
+ const int Hs = src.getHeight();
+ const int Wd = dst.getWidth();
+ const int Hd = dst.getHeight();
float col_scale = float (Ws) / float (Wd);
float row_scale = float (Hs) / float (Hd);
@@ -81,10 +81,10 @@ inline void rescaleBilinear(const array2D &src, array2D &dst, bool
inline void rescaleNearest(const array2D &src, array2D &dst, bool multithread)
{
- const int width = src.width();
- const int height = src.height();
- const int nw = dst.width();
- const int nh = dst.height();
+ const int width = src.getWidth();
+ const int height = src.getHeight();
+ const int nw = dst.getWidth();
+ const int nh = dst.getHeight();
#ifdef _OPENMP
#pragma omp parallel for if (multithread)
diff --git a/rtengine/settings.h b/rtengine/settings.h
index fde6fa132..0fb4996df 100644
--- a/rtengine/settings.h
+++ b/rtengine/settings.h
@@ -99,6 +99,10 @@ public:
int itcwb_delta;
bool itcwb_stdobserver10;
int itcwb_precis;
+//wavelet levels
+ double edghi;
+ double edglo;
+ double limrad;
enum class ThumbnailInspectorMode {
diff --git a/rtengine/tmo_fattal02.cc b/rtengine/tmo_fattal02.cc
index bef41d953..f49fe9c53 100644
--- a/rtengine/tmo_fattal02.cc
+++ b/rtengine/tmo_fattal02.cc
@@ -123,12 +123,12 @@ public:
int getRows() const
{
- return const_cast(*this).height();
+ return const_cast(*this).getHeight();
}
int getCols() const
{
- return const_cast(*this).width();
+ return const_cast(*this).getWidth();
}
float *data()
diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc
index 42a2263e2..34d6c8aa3 100644
--- a/rtgui/filecatalog.cc
+++ b/rtgui/filecatalog.cc
@@ -42,6 +42,7 @@
#include "pathutils.h"
#include "thumbnail.h"
#include "toolbar.h"
+#include "inspector.h"
using namespace std;
@@ -2508,6 +2509,15 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event)
}
}
+ if (!ctrl && !alt) {
+ switch (event->keyval) {
+ case GDK_KEY_f:
+ case GDK_KEY_F:
+ fileBrowser->getInspector()->showWindow(!shift);
+ return true;
+ }
+ }
+
return fileBrowser->keyPressed(event);
}
diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc
index 1a66aed7c..983a0840c 100644
--- a/rtgui/filepanel.cc
+++ b/rtgui/filepanel.cc
@@ -115,9 +115,9 @@ FilePanel::FilePanel () : parent(nullptr), error(0)
Gtk::Label* devLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_DEVELOP")) );
devLab->set_name ("LabelRightNotebook");
devLab->set_angle (90);
- Gtk::Label* inspectLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_INSPECT")) );
- inspectLab->set_name ("LabelRightNotebook");
- inspectLab->set_angle (90);
+ //Gtk::Label* inspectLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_INSPECT")) );
+ //inspectLab->set_name ("LabelRightNotebook");
+ //inspectLab->set_angle (90);
Gtk::Label* filtLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_FILTER")) );
filtLab->set_name ("LabelRightNotebook");
filtLab->set_angle (90);
@@ -132,7 +132,7 @@ FilePanel::FilePanel () : parent(nullptr), error(0)
tpcPaned->pack2 (*history, true, false);
rightNotebook->append_page (*sFilterPanel, *filtLab);
- rightNotebook->append_page (*inspectorPanel, *inspectLab);
+ //rightNotebook->append_page (*inspectorPanel, *inspectLab);
rightNotebook->append_page (*tpcPaned, *devLab);
//rightNotebook->append_page (*taggingBox, *tagLab); commented out: currently the tab is empty ...
rightNotebook->append_page (*sExportPanel, *exportLab);
diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc
index 9002cc389..7d5d44e44 100644
--- a/rtgui/inspector.cc
+++ b/rtgui/inspector.cc
@@ -82,9 +82,25 @@ InspectorBuffer::~InspectorBuffer() {
// return deg;
//}
-Inspector::Inspector () : currImage(nullptr), zoom(0.0), active(false)
+Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false)
{
set_name("Inspector");
+ window.set_visible(false);
+ window.set_title("RawTherapee Inspector");
+
+ window.add_events(Gdk::KEY_PRESS_MASK);
+ window.signal_key_release_event().connect(sigc::mem_fun(*this, &Inspector::on_key_release));
+ window.signal_key_press_event().connect(sigc::mem_fun(*this, &Inspector::on_key_press));
+
+ add_events(Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
+ gestureZoom = Gtk::GestureZoom::create(*this);
+ gestureZoom->signal_begin().connect(sigc::mem_fun(*this, &Inspector::on_zoom_begin));
+ gestureZoom->signal_scale_changed().connect(sigc::mem_fun(*this, &Inspector::on_zoom_scale_changed));
+
+ window.add(*this);
+ window.show_all();
+ window.set_visible(false);
+ active = true; // always track inspected thumbnails
}
Inspector::~Inspector()
@@ -92,8 +108,184 @@ Inspector::~Inspector()
deleteBuffers();
}
+void Inspector::showWindow(bool scaled)
+{
+ this->scaled = scaled;
+ window.fullscreen();
+ window.set_visible(true);
+ pinned = false;
+}
+
+bool Inspector::on_key_release(GdkEventKey *event)
+{
+ if (!pinned) {
+ switch (event->keyval) {
+ case GDK_KEY_f:
+ case GDK_KEY_F:
+ zoomScale = 1.0;
+ window.set_visible(false);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Inspector::on_key_press(GdkEventKey *event)
+{
+ switch (event->keyval) {
+ case GDK_KEY_z:
+ case GDK_KEY_F:
+ if (pinned || scaled)
+ zoomScale = 1.0; // reset if not key hold
+ scaled = false;
+ queue_draw();
+ return true;
+ case GDK_KEY_f:
+ if (pinned || !scaled)
+ zoomScale = 1.0; // reset if not key hold
+ scaled = true;
+ queue_draw();
+ return true;
+ case GDK_KEY_Escape:
+ zoomScale = 1.0;
+ window.set_visible(false);
+ return true;
+ }
+
+ return false;
+}
+
+bool Inspector::on_button_press_event(GdkEventButton *event)
+{
+ if (event->type == GDK_BUTTON_PRESS) {
+ if (!pinned)
+ // pin window with mouse click
+ pinned = true;
+ return true;
+ }
+ return false;
+}
+
+bool Inspector::on_scroll_event(GdkEventScroll *event)
+{
+ if (!currImage)
+ return false;
+
+ bool alt = event->state & GDK_MOD1_MASK;
+ int deviceScale = get_scale_factor();
+ int imW = currImage->imgBuffer.getWidth();
+ int imH = currImage->imgBuffer.getHeight();
+
+#ifdef GDK_WINDOWING_QUARTZ
+ // event reports speed of scroll wheel
+ double step_x = -event->delta_x;
+ double step_y = event->delta_y;
+#else
+ // assume fixed step of 5%
+ double step_x = 5;
+ double step_y = 5;
+#endif
+ int delta_x = 0;
+ int delta_y = 0;
+ switch (event->direction) {
+ case GDK_SCROLL_SMOOTH:
+#ifdef GDK_WINDOWING_QUARTZ
+ // no additional step for smooth scrolling
+ delta_x = event->delta_x * deviceScale;
+ delta_y = event->delta_y * deviceScale;
+#else
+ // apply step to smooth scrolling as well
+ delta_x = event->delta_x * deviceScale * step_x * imW / 100;
+ delta_y = event->delta_y * deviceScale * step_y * imH / 100;
+#endif
+ break;
+ case GDK_SCROLL_DOWN:
+ delta_y = step_y * deviceScale * imH / 100;
+ break;
+ case GDK_SCROLL_UP:
+ delta_y = -step_y * deviceScale * imH / 100;
+ break;
+ case GDK_SCROLL_LEFT:
+ delta_x = step_x * deviceScale * imW / 100;
+ break;
+ case GDK_SCROLL_RIGHT:
+ delta_x = -step_x * deviceScale * imW / 100;
+ break;
+ }
+
+ if (alt) {
+ // zoom
+ beginZoom(event->x, event->y);
+ if (std::fabs(delta_y) > std::fabs(delta_x))
+ on_zoom_scale_changed(1.0 - (double)delta_y / imH / deviceScale);
+ else
+ on_zoom_scale_changed(1.0 - (double)delta_x / imW / deviceScale);
+ return true;
+ }
+
+ // scroll
+ moveCenter(delta_x, delta_y, imW, imH, deviceScale);
+
+ if (!dirty) {
+ dirty = true;
+ queue_draw();
+ }
+
+ return true;
+}
+
+void Inspector::moveCenter(int delta_x, int delta_y, int imW, int imH, int deviceScale)
+{
+ rtengine::Coord margin; // limit to image size
+ margin.x = rtengine::min(window.get_width() * deviceScale / scale, imW) / 2;
+ margin.y = rtengine::min(window.get_height() * deviceScale / scale, imH) / 2;
+ center.set(rtengine::LIM(center.x + delta_x, margin.x, imW - margin.x),
+ rtengine::LIM(center.y + delta_y, margin.y, imH - margin.y));
+}
+
+void Inspector::beginZoom(double x, double y)
+{
+ int deviceScale = get_scale_factor();
+ int imW = currImage->imgBuffer.getWidth();
+ int imH = currImage->imgBuffer.getHeight();
+
+ // limit center to image size
+ moveCenter(0, 0, imW, imH, deviceScale);
+
+ // store center and current position for zooming
+ dcenterBegin.x = (x - window.get_width()/2) / scale * deviceScale;
+ dcenterBegin.y = (y - window.get_height()/2) / scale * deviceScale;
+ centerBegin = center;
+ zoomScaleBegin = zoomScale;
+
+}
+
+void Inspector::on_zoom_begin(GdkEventSequence *s)
+{
+ double x, y;
+ if (gestureZoom->get_point(s, x, y))
+ beginZoom(x, y);
+}
+
+void Inspector::on_zoom_scale_changed(double zscale)
+{
+ if (!currImage)
+ return;
+
+ zoomScale = rtengine::LIM(zoomScaleBegin * zscale, 0.01, 16.0);
+ double dcenterRatio = 1.0 - zoomScaleBegin / zoomScale;
+ center.x = centerBegin.x + dcenterBegin.x * dcenterRatio;
+ center.y = centerBegin.y + dcenterBegin.y * dcenterRatio;
+
+ if (!dirty) {
+ dirty = true;
+ queue_draw();
+ }
+}
+
bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
{
+ dirty = false;
Glib::RefPtr win = get_window();
@@ -116,10 +308,24 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
rtengine::Coord availableSize;
rtengine::Coord topLeft;
rtengine::Coord dest(0, 0);
- availableSize.x = win->get_width();
- availableSize.y = win->get_height();
- int imW = currImage->imgBuffer.getWidth();
- int imH = currImage->imgBuffer.getHeight();
+ int deviceScale = get_scale_factor();
+ availableSize.x = win->get_width() * deviceScale;
+ availableSize.y = win->get_height() * deviceScale;
+ int imW = rtengine::max(currImage->imgBuffer.getWidth(), 1);
+ int imH = rtengine::max(currImage->imgBuffer.getHeight(), 1);
+ scale = rtengine::min((double)availableSize.x / imW, (double)availableSize.y / imH);
+ if (scaled) {
+ // reduce size of image to fit into window, no further zoom down
+ zoomScale = rtengine::max(zoomScale, 1.0);
+ scale *= zoomScale;
+ }
+ else {
+ // limit zoom to fill at least complete window or 1:1
+ zoomScale = rtengine::max(zoomScale, rtengine::min(1.0, scale));
+ scale = zoomScale;
+ }
+ availableSize.x /= scale;
+ availableSize.y /= scale;
if (imW < availableSize.x) {
// center the image in the available space along X
@@ -146,7 +352,6 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
topLeft.y -= availableSize.y;
topLeft.y = rtengine::max(topLeft.y, 0);
}
-
//printf("center: %d, %d (img: %d, %d) (availableSize: %d, %d) (topLeft: %d, %d)\n", center.x, center.y, imW, imH, availableSize.x, availableSize.y, topLeft.x, topLeft.y);
// define the destination area
@@ -163,24 +368,50 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
Glib::RefPtr style = get_style_context();
// draw the background
- style->render_background(cr, 0, 0, get_width(), get_height());
+ //style->render_background(cr, 0, 0, get_width(), get_height());
- /* --- old method
+ ///* --- old method (the new method does not seem to work)
c = style->get_background_color (Gtk::STATE_FLAG_NORMAL);
cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue());
cr->set_line_width (0);
cr->rectangle (0, 0, availableSize.x, availableSize.y);
cr->fill ();
- */
+ //*/
- currImage->imgBuffer.copySurface(win);
+ bool scaledImage = scale != 1.0;
+ if (deviceScale == 1 && !scaledImage) {
+ // standard drawing
+ currImage->imgBuffer.copySurface(win);
+ }
+ else {
+ // consider device scale and image scale
+ if (deviceScale > 1) {
+ // use full device resolution and let it scale the image (macOS)
+ cairo_surface_set_device_scale(cr->get_target()->cobj(), scale, scale);
+ scaledImage = false;
+ }
+ int viewW = rtengine::min(imW, availableSize.x);
+ int viewH = rtengine::min(imH, availableSize.y);
+ Glib::RefPtr crop = Gdk::Pixbuf::create(currImage->imgBuffer.getSurface(), topLeft.x, topLeft.y, viewW, viewH);
+ if (!scaledImage) {
+ Gdk::Cairo::set_source_pixbuf(cr, crop, dest.x, dest.y);
+ }
+ else {
+ // scale crop as the device does not seem to support it (Linux)
+ crop = crop->scale_simple(viewW*scale, viewH*scale, Gdk::INTERP_BILINEAR);
+ Gdk::Cairo::set_source_pixbuf(cr, crop, dest.x*scale, dest.y*scale);
+ }
+ cr->paint();
+ }
+ /* --- not for separate window
// draw the frame
c = style->get_border_color (Gtk::STATE_FLAG_NORMAL);
cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue());
cr->set_line_width (1);
cr->rectangle (0.5, 0.5, availableSize.x - 1, availableSize.y - 1);
cr->stroke ();
+ */
}
return true;
@@ -309,7 +540,7 @@ void Inspector::setActive(bool state)
flushBuffers();
}
- active = state;
+ //active = state;
}
diff --git a/rtgui/inspector.h b/rtgui/inspector.h
index 1526f90be..9a99fb8a6 100644
--- a/rtgui/inspector.h
+++ b/rtgui/inspector.h
@@ -47,12 +47,30 @@ private:
rtengine::Coord center;
std::vector images;
InspectorBuffer* currImage;
- double zoom;
+ bool scaled; // fit image into window
+ double scale; // current scale
+ double zoomScale, zoomScaleBegin; // scale during zoom
+ rtengine::Coord centerBegin, dcenterBegin; // center during zoom
bool active;
+ bool pinned;
+ bool dirty;
sigc::connection delayconn;
Glib::ustring next_image_path;
+ Gtk::Window window;
+ bool on_key_release(GdkEventKey *event);
+ bool on_key_press(GdkEventKey *event);
+
+ bool on_button_press_event(GdkEventButton *event) override;
+ bool on_scroll_event(GdkEventScroll *event) override;
+ void moveCenter(int delta_x, int delta_y, int imW, int imH, int deviceScale);
+
+ Glib::RefPtr gestureZoom;
+ void beginZoom(double x, double y);
+ void on_zoom_begin(GdkEventSequence *);
+ void on_zoom_scale_changed(double zscale);
+
bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override;
void deleteBuffers();
@@ -62,6 +80,11 @@ public:
Inspector();
~Inspector() override;
+ /** @brief Show or hide window
+ * @param scaled fit image into window
+ */
+ void showWindow(bool scaled);
+
/** @brief Mouse movement to a new position
* @param pos Location of the mouse, in percentage (i.e. [0;1] range) relative to the full size image ; -1,-1 == out of the image
* @param transform H/V flip and coarse rotation transformation
diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc
index 5f4febc0a..27a8bee52 100644
--- a/rtgui/labcurve.cc
+++ b/rtgui/labcurve.cc
@@ -663,6 +663,8 @@ void LCurve::updateCurveBackgroundHistogram(
{
lshape->updateBackgroundHistogram (histLCurve);
ccshape->updateBackgroundHistogram (histCCurve);
+ lcshape->updateBackgroundHistogram (histCCurve);
+ clshape->updateBackgroundHistogram (histLCurve);
}
void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd)
diff --git a/rtgui/options.cc b/rtgui/options.cc
index b7eb9f810..79c62efa7 100644
--- a/rtgui/options.cc
+++ b/rtgui/options.cc
@@ -618,6 +618,12 @@ void Options::setDefaults()
rtSettings.itcwb_precis = 5;//3 or 5 or 9
// end locallab
+//wavelet
+ rtSettings.edghi = 3.0;//1.1 and 5.
+ rtSettings.edglo = 0.5;//0.1 and 0.95
+ rtSettings.limrad = 20.;//1 and 60
+
+
rtSettings.protectred = 60;
rtSettings.protectredh = 0.3;
rtSettings.CRI_color = 0;
@@ -1709,6 +1715,22 @@ void Options::readFromFile(Glib::ustring fname)
}
+ if (keyFile.has_group("Wavelet")) {
+ if (keyFile.has_key("Wavelet", "Edghi")) {
+ rtSettings.edghi = keyFile.get_double("Wavelet", "Edghi");
+ }
+
+ if (keyFile.has_key("Wavelet", "Edglo")) {
+ rtSettings.edglo = keyFile.get_double("Wavelet", "Edglo");
+ }
+
+ if (keyFile.has_key("Wavelet", "Limrad")) {
+ rtSettings.limrad = keyFile.get_double("Wavelet", "Limrad");
+ }
+
+ }
+
+
if (keyFile.has_group("ICC Profile Creator")) {
if (keyFile.has_key("ICC Profile Creator", "PimariesPreset")) {
ICCPC_primariesPreset = keyFile.get_string("ICC Profile Creator", "PimariesPreset");
@@ -2308,6 +2330,11 @@ void Options::saveToFile(Glib::ustring fname)
keyFile.set_integer("Color Management", "Previewselection", rtSettings.previewselection);
keyFile.set_double("Color Management", "Cbdlsensi", rtSettings.cbdlsensi);
+ keyFile.set_double("Wavelet", "Edghi", rtSettings.edghi);
+ keyFile.set_double("Wavelet", "Edglo", rtSettings.edglo);
+ keyFile.set_double("Wavelet", "Limrad", rtSettings.limrad);
+
+
keyFile.set_string("ICC Profile Creator", "PimariesPreset", ICCPC_primariesPreset);
keyFile.set_double("ICC Profile Creator", "RedPrimaryX", ICCPC_redPrimaryX);
keyFile.set_double("ICC Profile Creator", "RedPrimaryY", ICCPC_redPrimaryY);
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index db830c6c1..3cd93064e 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -60,6 +60,7 @@ void ParamsEdited::set(bool v)
retinex.mapcurve = v;
retinex.cdHcurve = v;
retinex.lhcurve = v;
+ retinex.complexmethod = v;
retinex.retinexMethod = v;
retinex.mapMethod = v;
retinex.viewMethod = v;
@@ -531,6 +532,7 @@ void ParamsEdited::set(bool v)
wavelet.CLmethod = v;
wavelet.Backmethod = v;
wavelet.Tilesmethod = v;
+ wavelet.complexmethod = v;
wavelet.daubcoeffmethod = v;
wavelet.CHmethod = v;
wavelet.CHSLmethod = v;
@@ -710,6 +712,7 @@ void ParamsEdited::initFrom(const std::vector&
retinex.lhcurve = retinex.lhcurve && p.retinex.lhcurve == other.retinex.lhcurve;
retinex.transmissionCurve = retinex.transmissionCurve && p.retinex.transmissionCurve == other.retinex.transmissionCurve;
retinex.gaintransmissionCurve = retinex.gaintransmissionCurve && p.retinex.gaintransmissionCurve == other.retinex.gaintransmissionCurve;
+ retinex.complexmethod = retinex.complexmethod && p.retinex.complexmethod == other.retinex.complexmethod;
retinex.retinexMethod = retinex.retinexMethod && p.retinex.retinexMethod == other.retinex.retinexMethod;
retinex.mapMethod = retinex.mapMethod && p.retinex.mapMethod == other.retinex.mapMethod;
retinex.viewMethod = retinex.viewMethod && p.retinex.viewMethod == other.retinex.viewMethod;
@@ -1679,6 +1682,7 @@ void ParamsEdited::initFrom(const std::vector&
wavelet.CLmethod = wavelet.CLmethod && p.wavelet.CLmethod == other.wavelet.CLmethod;
wavelet.Backmethod = wavelet.Backmethod && p.wavelet.Backmethod == other.wavelet.Backmethod;
wavelet.Tilesmethod = wavelet.Tilesmethod && p.wavelet.Tilesmethod == other.wavelet.Tilesmethod;
+ wavelet.complexmethod = wavelet.complexmethod && p.wavelet.complexmethod == other.wavelet.complexmethod;
wavelet.daubcoeffmethod = wavelet.daubcoeffmethod && p.wavelet.daubcoeffmethod == other.wavelet.daubcoeffmethod;
wavelet.CHmethod = wavelet.CHmethod && p.wavelet.CHmethod == other.wavelet.CHmethod;
wavelet.CHSLmethod = wavelet.CHSLmethod && p.wavelet.CHSLmethod == other.wavelet.CHSLmethod;
@@ -1915,6 +1919,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
toEdit.retinex.gaintransmissionCurve = mods.retinex.gaintransmissionCurve;
}
+ if (retinex.complexmethod) {
+ toEdit.retinex.complexmethod = mods.retinex.complexmethod;
+ }
+
if (retinex.retinexMethod) {
toEdit.retinex.retinexMethod = mods.retinex.retinexMethod;
}
@@ -5574,6 +5582,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
toEdit.wavelet.Tilesmethod = mods.wavelet.Tilesmethod;
}
+ if (wavelet.complexmethod) {
+ toEdit.wavelet.complexmethod = mods.wavelet.complexmethod;
+ }
+
if (wavelet.daubcoeffmethod) {
toEdit.wavelet.daubcoeffmethod = mods.wavelet.daubcoeffmethod;
}
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index 98a427796..f8230a577 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -73,6 +73,7 @@ struct RetinexParamsEdited {
bool slope;
bool neigh;
bool offs;
+ bool complexmethod;
bool retinexMethod;
bool mapMethod;
bool viewMethod;
@@ -1039,6 +1040,7 @@ struct WaveletParamsEdited {
bool CLmethod;
bool Backmethod;
bool Tilesmethod;
+ bool complexmethod;
bool daubcoeffmethod;
bool Dirmethod;
bool sigma;
diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc
index 2fdd8f319..feab8e6a5 100644
--- a/rtgui/retinex.cc
+++ b/rtgui/retinex.cc
@@ -9,6 +9,7 @@
#include "rtimage.h"
#include "options.h"
#include "../rtengine/color.h"
+#include "eventmapper.h"
using namespace rtengine;
using namespace rtengine::procparams;
@@ -25,13 +26,26 @@ Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL")
nextsigma = 0.;
nextminT = 0.;
nextmaxT = 0.;
+ auto m = ProcEventMapper::getInstance();
+ EvReticomplex = m->newEvent(DEMOSAIC, "HISTORY_MSG_COMPLEXRETI");
+ const RetinexParams default_params;
// MAIN Expander ==================================================================
+ complexmethod = Gtk::manage (new MyComboBoxText ());
+ complexmethod->append(M("TP_WAVELET_COMPNORMAL"));
+ complexmethod->append(M("TP_WAVELET_COMPEXPERT"));
+ complexmethodconn = complexmethod->signal_changed().connect(sigc::mem_fun(*this, &Retinex::complexmethodChanged));
+ complexmethod->set_tooltip_text(M("TP_WAVELET_COMPLEX_TOOLTIP"));
+ Gtk::HBox* const complexHBox = Gtk::manage(new Gtk::HBox());
+ Gtk::Label* const complexLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_COMPLEXLAB") + ":"));
+ complexHBox->pack_start(*complexLabel, Gtk::PACK_SHRINK, 4);
+ complexHBox->pack_start(*complexmethod);
+ pack_start(*complexHBox);
Gtk::Grid *retinexGrid = Gtk::manage ( new Gtk::Grid());
@@ -116,7 +130,8 @@ Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL")
// MAP (MASK) Frame ---------------------------------------------------------------
- Gtk::Frame *maskFrame = Gtk::manage (new Gtk::Frame (M ("TP_RETINEX_LABEL_MASK")) );
+ // Gtk::Frame *maskFrame = Gtk::manage (new Gtk::Frame (M ("TP_RETINEX_LABEL_MASK")) );
+ maskFrame = Gtk::manage (new Gtk::Frame (M ("TP_RETINEX_LABEL_MASK")) );
setExpandAlignProperties (maskFrame, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START);
Gtk::Grid *maskGrid = Gtk::manage ( new Gtk::Grid());
@@ -384,7 +399,6 @@ Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL")
Gtk::Grid *tranGrid = Gtk::manage (new Gtk::Grid());
setExpandAlignProperties (tranGrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START);
- const RetinexParams default_params;
// Transmission map curve
transmissionCurveEditorG = new CurveEditorGroup (options.lastRetinexDir, M ("TP_RETINEX_TRANSMISSION"));
@@ -628,12 +642,14 @@ void Retinex::neutral_pressed ()
limd->resetValue (false);
highl->resetValue (false);
gam->resetValue (false);
+ skal->resetValue (false);
slope->resetValue (false);
highlights->resetValue (false);
h_tonalwidth->resetValue (false);
shadows->resetValue (false);
s_tonalwidth->resetValue (false);
radius->resetValue (false);
+ medianmap->set_active (false);
mapMethod->set_active (0);
viewMethod->set_active (0);
retinexMethod->set_active (2);
@@ -742,7 +758,53 @@ void Retinex::updateTrans ()
}
}
+void Retinex::convertParamToNormal()
+{
+ const RetinexParams def_params;
+ disableListener();
+ iter->setValue(def_params.iter);
+ viewMethod->set_active(0);
+ mapMethod->set_active(0);
+ cdshape->reset();
+ cdshapeH->reset();
+ lhshape->reset();
+ transmissionShape->reset();
+ medianmap->set_active(def_params.medianmap);
+ enableListener();
+}
+void Retinex::updateGUIToMode(int mode)
+{
+
+ if(mode ==0) {
+ iterFrame->hide();
+ maskFrame->hide();
+ equalFrame->hide();
+ viewMethod->hide();
+ mapMethod->hide();
+ transmissionCurveEditorG->hide();
+ medianmap->hide();
+ } else {
+ iterFrame->show();
+ maskFrame->show();
+ equalFrame->show();
+ viewMethod->show();
+ transmissionCurveEditorG->show();
+ medianmap->show();
+ mapMethod->show();
+ if (iter->getIntValue() > 1) {
+ grad->set_sensitive (true);
+ scal->set_sensitive (true);
+ grads->set_sensitive (true);
+ } else {
+ grad->set_sensitive (false);
+ scal->set_sensitive (false);
+ grads->set_sensitive (false);
+ }
+
+ }
+
+}
void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
{
@@ -752,6 +814,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
gammaretinexConn.block (true);
mapMethodConn.block (true);
viewMethodConn.block (true);
+ complexmethodconn.block (true);
if (pedited) {
@@ -775,6 +838,9 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
shadows->setEditedState (pedited->retinex.shadows ? Edited : UnEdited);
s_tonalwidth->setEditedState (pedited->retinex.stonalwidth ? Edited : UnEdited);
+ if (!pedited->retinex.complexmethod) {
+ complexmethod->set_active_text (M ("GENERAL_UNCHANGED"));
+ }
if (!pedited->retinex.retinexMethod) {
retinexMethod->set_active_text (M ("GENERAL_UNCHANGED"));
@@ -844,6 +910,13 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
medianmapConn.block (false);
lastmedianmap = pp->retinex.medianmap;
+ if (pp->retinex.complexmethod == "normal") {
+ complexmethod->set_active(0);
+ } else if (pp->retinex.complexmethod == "expert") {
+ complexmethod->set_active(1);
+ }
+
+
if (pp->retinex.retinexMethod == "low") {
retinexMethod->set_active (0);
} else if (pp->retinex.retinexMethod == "uni") {
@@ -906,6 +979,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
mapMethodChanged ();
viewMethodChanged ();
+
medianmapConn.block (true);
medianmapChanged ();
medianmapConn.block (false);
@@ -914,7 +988,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
cdshapeH->setCurve (pp->retinex.cdHcurve);
lhshape->setCurve (pp->retinex.lhcurve);
mapshape->setCurve (pp->retinex.mapcurve);
-
+
retinexMethodConn.block (false);
retinexColorSpaceConn.block (false);
gammaretinexConn.block (false);
@@ -923,8 +997,18 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
transmissionShape->setCurve (pp->retinex.transmissionCurve);
gaintransmissionShape->setCurve (pp->retinex.gaintransmissionCurve);
+ complexmethodconn.block (false);
enableListener ();
+
+ if (complexmethod->get_active_row_number() == 0) {
+ updateGUIToMode(0);
+ // convertParamToNormal();
+
+ } else {
+ updateGUIToMode(1);
+ }
+
}
@@ -961,6 +1045,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited)
pp->retinex.stonalwidth = (int)s_tonalwidth->getValue ();
if (pedited) {
+ pedited->retinex.complexmethod = complexmethod->get_active_text() != M ("GENERAL_UNCHANGED");
pedited->retinex.retinexMethod = retinexMethod->get_active_text() != M ("GENERAL_UNCHANGED");
pedited->retinex.retinexcolorspace = retinexcolorspace->get_active_text() != M ("GENERAL_UNCHANGED");
pedited->retinex.gammaretinex = gammaretinex->get_active_text() != M ("GENERAL_UNCHANGED");
@@ -998,6 +1083,12 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited)
}
+ if (complexmethod->get_active_row_number() == 0) {
+ pp->retinex.complexmethod = "normal";
+ } else if (complexmethod->get_active_row_number() == 1) {
+ pp->retinex.complexmethod = "expert";
+ }
+
if (retinexMethod->get_active_row_number() == 0) {
pp->retinex.retinexMethod = "low";
} else if (retinexMethod->get_active_row_number() == 1) {
@@ -1056,6 +1147,27 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited)
}
+void Retinex::complexmethodChanged()
+{
+
+ if (!batchMode) {
+ if (complexmethod->get_active_row_number() == 0) {
+ updateGUIToMode(0);
+ convertParamToNormal();
+
+ } else {
+ updateGUIToMode(1);
+ }
+ }
+
+ if (listener) {
+ listener->panelChanged(EvReticomplex, complexmethod->get_active_text());
+ }
+
+}
+
+
+
void Retinex::retinexMethodChanged()
{
@@ -1138,8 +1250,11 @@ void Retinex::viewMethodChanged()
limd->show();
transmissionCurveEditorG->show();
medianmap->show();
-
- iterFrame->show();
+ if (complexmethod->get_active_row_number() == 0) {
+ iterFrame->hide();
+ } else {
+ iterFrame->show();
+ }
/*
iter->show();
scal->show();
@@ -1522,6 +1637,7 @@ void Retinex::setBatchMode (bool batchMode)
h_tonalwidth->showEditedCB ();
shadows->showEditedCB ();
s_tonalwidth->showEditedCB ();
+ // complexmethod->append(M("GENERAL_UNCHANGED"));
skal->showEditedCB ();
curveEditorGD->setBatchMode (batchMode);
diff --git a/rtgui/retinex.h b/rtgui/retinex.h
index dea65daab..bf480c9cc 100644
--- a/rtgui/retinex.h
+++ b/rtgui/retinex.h
@@ -28,6 +28,7 @@ class Retinex final :
{
private:
IdleRegister idle_register;
+ rtengine::ProcEvent EvReticomplex;
protected:
CurveEditorGroup* curveEditorGD;
@@ -72,6 +73,9 @@ protected:
MyComboBoxText* mapMethod;
MyComboBoxText* viewMethod;
Gtk::CheckButton* medianmap;
+ MyComboBoxText* complexmethod;
+ sigc::connection complexmethodconn;
+
double nextmin;
double nextmax;
double nextminiT;
@@ -87,6 +91,7 @@ protected:
Gtk::Frame *gainFrame;
Gtk::Frame *tranFrame;
Gtk::Frame *iterFrame;
+ Gtk::Frame *maskFrame;
Gtk::Frame *equalFrame;
DiagonalCurveEditor* cdshape;
@@ -148,4 +153,7 @@ public:
private:
void foldAllButMe(GdkEventButton* event, MyExpander *expander);
+ void convertParamToNormal();
+ void updateGUIToMode(int mode);
+ void complexmethodChanged();
};
diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc
index ac8c6100b..19d458dad 100644
--- a/rtgui/wavelet.cc
+++ b/rtgui/wavelet.cc
@@ -158,6 +158,7 @@ Wavelet::Wavelet() :
HSmethod(Gtk::manage(new MyComboBoxText())),
CLmethod(Gtk::manage(new MyComboBoxText())),
Backmethod(Gtk::manage(new MyComboBoxText())),
+ complexmethod(Gtk::manage(new MyComboBoxText())),
Tilesmethod(Gtk::manage(new MyComboBoxText())),
daubcoeffmethod(Gtk::manage(new MyComboBoxText())),
Dirmethod(Gtk::manage(new MyComboBoxText())),
@@ -190,7 +191,10 @@ Wavelet::Wavelet() :
expclari(Gtk::manage(new MyExpander(true, M("TP_WAVELET_CLARI")))),
expbl(Gtk::manage(new MyExpander(true, M("TP_WAVELET_BL")))),
neutrHBox(Gtk::manage(new Gtk::HBox())),
- usharpHBox(Gtk::manage(new Gtk::HBox()))
+ usharpHBox(Gtk::manage(new Gtk::HBox())),
+ ctboxch(Gtk::manage(new Gtk::HBox())),
+ ctboxBA(Gtk::manage(new Gtk::VBox()))
+
{
CurveListener::setMulti(true);
auto m = ProcEventMapper::getInstance();
@@ -227,6 +231,7 @@ Wavelet::Wavelet() :
EvWavrangeab = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_RANGEAB");
EvWavprotab = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_PROTAB");
EvWavlevelshc = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_LEVELSHC");
+ EvWavcomplexmet = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_COMPLEX");
labgrid = Gtk::manage(new LabGrid(EvWavLabGridValue, M("TP_WAVELET_LABGRID_VALUES")));
@@ -269,6 +274,16 @@ Wavelet::Wavelet() :
thres->set_tooltip_text(M("TP_WAVELET_LEVELS_TOOLTIP"));
thres->setAdjusterListener(this);
+ complexmethod->append(M("TP_WAVELET_COMPNORMAL"));
+ complexmethod->append(M("TP_WAVELET_COMPEXPERT"));
+ complexmethodconn = complexmethod->signal_changed().connect(sigc::mem_fun(*this, &Wavelet::complexmethodChanged));
+ complexmethod->set_tooltip_text(M("TP_WAVELET_COMPLEX_TOOLTIP"));
+ Gtk::HBox* const complexHBox = Gtk::manage(new Gtk::HBox());
+ Gtk::Label* const complexLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_COMPLEXLAB") + ":"));
+ complexHBox->pack_start(*complexLabel, Gtk::PACK_SHRINK, 4);
+ complexHBox->pack_start(*complexmethod);
+
+
Tilesmethod->append(M("TP_WAVELET_TILESFULL"));
Tilesmethod->append(M("TP_WAVELET_TILESBIG"));
// Tilesmethod->append(M("TP_WAVELET_TILESLIT"));
@@ -335,6 +350,7 @@ Wavelet::Wavelet() :
levdirSubHBox->pack_start(*Lmethod);
levdirSubHBox->pack_start(*Dirmethod, Gtk::PACK_EXPAND_WIDGET, 2); // same, but 2 not 4?
+ settingsBox->pack_start(*complexHBox);
settingsBox->pack_start(*strength);
settingsBox->pack_start(*thres);
settingsBox->pack_start(*tilesizeHBox);
@@ -452,7 +468,7 @@ Wavelet::Wavelet() :
ToolParamBlock* const chBox = Gtk::manage(new ToolParamBlock());
Gtk::Label* const labmch = Gtk::manage(new Gtk::Label(M("TP_WAVELET_CHTYPE") + ":"));
- Gtk::HBox* const ctboxch = Gtk::manage(new Gtk::HBox());
+// Gtk::HBox* const ctboxch = Gtk::manage(new Gtk::HBox());
ctboxch->pack_start(*labmch, Gtk::PACK_SHRINK, 1);
CHmethod->append(M("TP_WAVELET_CH1"));
@@ -674,7 +690,7 @@ Wavelet::Wavelet() :
EDmethod->append(M("TP_WAVELET_EDCU"));
EDmethodconn = EDmethod->signal_changed().connect(sigc::mem_fun(*this, &Wavelet::EDmethodChanged));
ctboxED->pack_start(*EDmethod);
- edgBox->pack_start(*ctboxED);
+ // edgBox->pack_start(*ctboxED);
edgcont->setAdjusterListener(this);
edgcont->setBgGradient(milestones2);
@@ -838,7 +854,7 @@ Wavelet::Wavelet() :
thrH->setAdjusterListener(this);
radius->setAdjusterListener(this);
- radius->hide();
+// radius->hide();
shFrame->set_label_align(0.025, 0.5);
ToolParamBlock* const shBox = Gtk::manage(new ToolParamBlock());
@@ -1007,7 +1023,7 @@ Wavelet::Wavelet() :
resBox->pack_start(*neutrHBox);
// Final Touchup
- Gtk::VBox* const ctboxBA = Gtk::manage(new Gtk::VBox());
+ // Gtk::VBox* const ctboxBA = Gtk::manage(new Gtk::VBox());
ctboxBA->set_spacing(2);
@@ -1236,6 +1252,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited)
CLmethodconn.block(true);
Backmethodconn.block(true);
Tilesmethodconn.block(true);
+ complexmethodconn.block(true);
daubcoeffmethodconn.block(true);
Dirmethodconn.block(true);
CHmethodconn.block(true);
@@ -1357,6 +1374,12 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited)
} else if (pp->wavelet.CLmethod == "all") {
CLmethod->set_active(3);
}
+ if (pp->wavelet.complexmethod == "normal") {
+ complexmethod->set_active(0);
+ } else if (pp->wavelet.complexmethod == "expert") {
+ complexmethod->set_active(1);
+ }
+
//Tilesmethod->set_active (2);
if (pp->wavelet.Tilesmethod == "full") {
@@ -1558,6 +1581,11 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited)
Backmethod->set_active_text(M("GENERAL_UNCHANGED"));
}
+ if (!pedited->wavelet.complexmethod) {
+ complexmethod->set_active_text(M("GENERAL_UNCHANGED"));
+ }
+
+
if (!pedited->wavelet.Tilesmethod) {
Tilesmethod->set_active_text(M("GENERAL_UNCHANGED"));
}
@@ -1774,6 +1802,15 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited)
} else {
sup->hide();
}
+
+ if (complexmethod->get_active_row_number() == 0) {
+ updateGUIToMode(0);
+ convertParamToNormal();
+
+ } else {
+ updateGUIToMode(1);
+ }
+
}
/*****************************************************************************************************
@@ -1786,6 +1823,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited)
CLmethodconn.block(false);
Backmethodconn.block(false);
Tilesmethodconn.block(false);
+ complexmethodconn.block(false);
daubcoeffmethodconn.block(false);
CHmethodconn.block(false);
CHSLmethodconn.block(false);
@@ -1965,6 +2003,7 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited)
pedited->wavelet.CLmethod = CLmethod->get_active_text() != M("GENERAL_UNCHANGED");
pedited->wavelet.Backmethod = Backmethod->get_active_text() != M("GENERAL_UNCHANGED");
pedited->wavelet.Tilesmethod = Tilesmethod->get_active_text() != M("GENERAL_UNCHANGED");
+ pedited->wavelet.complexmethod = complexmethod->get_active_text() != M("GENERAL_UNCHANGED");
pedited->wavelet.daubcoeffmethod = daubcoeffmethod->get_active_text() != M("GENERAL_UNCHANGED");
pedited->wavelet.CHmethod = CHmethod->get_active_text() != M("GENERAL_UNCHANGED");
pedited->wavelet.CHSLmethod = CHSLmethod->get_active_text() != M("GENERAL_UNCHANGED");
@@ -2168,6 +2207,12 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited)
// pp->wavelet.Tilesmethod = "lit";
}
+ if (complexmethod->get_active_row_number() == 0) {
+ pp->wavelet.complexmethod = "normal";
+ } else if (complexmethod->get_active_row_number() == 1) {
+ pp->wavelet.complexmethod = "expert";
+ }
+
if (daubcoeffmethod->get_active_row_number() == 0) {
pp->wavelet.daubcoeffmethod = "2_";
} else if (daubcoeffmethod->get_active_row_number() == 1) {
@@ -2835,6 +2880,110 @@ void Wavelet::ushamethodChanged()
}
+
+void Wavelet::convertParamToNormal()
+{
+ const WaveletParams def_params;
+ disableListener();
+ //contrast
+ offset->setValue(def_params.offset);
+ sigma->setValue(def_params.sigma);
+ lowthr->setValue(def_params.lowthr);
+ //chroma
+ expchroma->setEnabled(def_params.expchroma);
+ sigmacol->setValue(def_params.sigmacol);
+ CHmethod->set_active(2);
+ //denoise
+ chromfi->setValue(def_params.chromfi);
+ chromco->setValue(def_params.chromco);
+ //toning
+ exptoning->setEnabled(def_params.exptoning);
+ //gamut
+ median->set_active(def_params.median);
+ avoid->set_active(def_params.avoid);
+ hueskin->setValue(def_params.hueskin);
+ skinprotect->setValue(def_params.skinprotect);
+ //blur
+ expbl->setEnabled(def_params.expbl);
+ //edge sharpness
+ lipst->set_active(def_params.lipst);
+ lipstUpdateUI();
+ edgesensi->setValue(def_params.edgesensi);
+ edgeampli->setValue(def_params.edgeampli);
+ NPmethod->set_active(0);
+ //resid
+ // oldsh->set_active(true);
+ radius->setValue(def_params.radius);
+ resblur->setValue(def_params.resblur);
+ resblurc->setValue(def_params.resblurc);
+ cbenab->set_active(false);
+
+ //final touchup
+ BAmethod->set_active(0);
+ sigmafin->setValue(def_params.sigmafin);
+ enableListener();
+
+ // Update GUI based on converted widget parameters:
+}
+
+void Wavelet::updateGUIToMode(int mode)
+{
+ if(mode ==0) {
+ offset->hide();
+ sigma->hide();
+ lowthr->hide();
+ ctboxch->hide();
+ sigmacol->hide();
+ expgamut->hide();
+ exptoning->hide();
+ chroFrame->hide();
+ expbl->hide();
+ lipst->hide();
+ dirFrame->hide();
+ oldsh->hide();
+ radius->hide();
+ blurFrame->hide();
+ cbenab->hide();
+ sigmafin->hide();
+ } else {
+ offset->show();
+ sigma->show();
+ lowthr->show();
+ ctboxch->show();
+ sigmacol->show();
+ expgamut->show();
+ exptoning->show();
+ chroFrame->show();
+ expbl->show();
+ lipst->show();
+ dirFrame->show();
+ oldsh->hide();
+ radius->show();
+ blurFrame->show();
+ cbenab->show();
+ sigmafin->show();
+ }
+
+}
+
+
+void Wavelet::complexmethodChanged()
+{
+ if (complexmethod->get_active_row_number() == 0) {
+ updateGUIToMode(0);
+ convertParamToNormal();
+
+ } else {
+ updateGUIToMode(1);
+ }
+
+ if (listener && (multiImage || getEnabled())) {
+ listener->panelChanged(EvWavcomplexmet, complexmethod->get_active_text());
+ }
+}
+
+
+
void Wavelet::TilesmethodChanged()
{
//TilesmethodUpdateUI();
@@ -2916,6 +3065,7 @@ void Wavelet::setBatchMode(bool batchMode)
CLmethod->append(M("GENERAL_UNCHANGED"));
Backmethod->append(M("GENERAL_UNCHANGED"));
Tilesmethod->append(M("GENERAL_UNCHANGED"));
+ complexmethod->append(M("GENERAL_UNCHANGED"));
daubcoeffmethod->append(M("GENERAL_UNCHANGED"));
CHmethod->append(M("GENERAL_UNCHANGED"));
Medgreinf->append(M("GENERAL_UNCHANGED"));
diff --git a/rtgui/wavelet.h b/rtgui/wavelet.h
index 6daabcd67..a497d2c4f 100644
--- a/rtgui/wavelet.h
+++ b/rtgui/wavelet.h
@@ -47,7 +47,6 @@ class Wavelet final :
public:
Wavelet();
~Wavelet() override;
-
bool wavComputed_();
void adjusterChanged(Adjuster* a, double newval) override;
void autoOpenCurve() override;
@@ -102,6 +101,7 @@ private:
rtengine::ProcEvent EvWavrangeab;
rtengine::ProcEvent EvWavprotab;
rtengine::ProcEvent EvWavlevelshc;
+ rtengine::ProcEvent EvWavcomplexmet;
LabGrid *labgrid;
@@ -121,6 +121,7 @@ private:
void LmethodChanged();
void MedgreinfChanged();
void TMmethodChanged();
+ void complexmethodChanged();
void TilesmethodChanged();
void avoidToggled();
void showmaskToggled ();
@@ -143,7 +144,8 @@ private:
void ushamethodChanged();
void updateGUI();
void updateGUImaxlev();
-
+ void convertParamToNormal();
+ void updateGUIToMode(int mode);
void HSmethodUpdateUI();
void CHmethodUpdateUI();
// void CHSLmethodChangedUI();
@@ -297,6 +299,8 @@ private:
sigc::connection CLmethodconn;
MyComboBoxText* const Backmethod;
sigc::connection Backmethodconn;
+ MyComboBoxText* const complexmethod;
+ sigc::connection complexmethodconn;
MyComboBoxText* const Tilesmethod;
sigc::connection Tilesmethodconn;
MyComboBoxText* const daubcoeffmethod;
@@ -338,6 +342,8 @@ private:
Gtk::HBox* const neutrHBox;
Gtk::HBox* const usharpHBox;
+ Gtk::HBox* const ctboxch;
+ Gtk::VBox* const ctboxBA;// = Gtk::manage(new Gtk::VBox());
sigc::connection enableChromaConn, enableContrastConn, enableEdgeConn, enabletmConn, enableFinalConn, enableclariConn;
sigc::connection enableNoiseConn, enableResidConn, enableToningConn;