4444#define exposure2white (x ) exp2f(-(x))
4545#define white2exposure (x ) -dt_log2f(fmaxf(1e-20f, x))
4646
47- DT_MODULE_INTROSPECTION (6 , dt_iop_exposure_params_t )
47+ DT_MODULE_INTROSPECTION (7 , dt_iop_exposure_params_t )
4848
4949typedef enum dt_iop_exposure_mode_t
5050{
@@ -71,6 +71,7 @@ typedef struct dt_iop_exposure_params_t
7171 float deflicker_percentile ; // $MIN: 0.0 $MAX: 100.0 $DEFAULT: 50.0 $DESCRIPTION: "percentile"
7272 float deflicker_target_level ; // $MIN: -18.0 $MAX: 18.0 $DEFAULT: -4.0 $DESCRIPTION: "target level"
7373 gboolean compensate_exposure_bias ;// $DEFAULT: FALSE $DESCRIPTION: "compensate exposure bias"
74+ gboolean compensate_hilite_pres ; // $DEFAULT: TRUE $DESCRIPTION: "compensate highlight preservation"
7475} dt_iop_exposure_params_t ;
7576
7677typedef struct dt_iop_exposure_gui_data_t
@@ -85,6 +86,7 @@ typedef struct dt_iop_exposure_gui_data_t
8586 dt_dev_histogram_stats_t deflicker_histogram_stats ;
8687 GtkLabel * deflicker_used_EC ;
8788 GtkWidget * compensate_exposure_bias ;
89+ GtkWidget * compensate_hilite_preserv ;
8890 float deflicker_computed_exposure ;
8991
9092 GtkWidget * spot_mode ;
@@ -168,6 +170,17 @@ int legacy_params(dt_iop_module_t *self,
168170 gboolean compensate_exposure_bias ;
169171 } dt_iop_exposure_params_v6_t ;
170172
173+ typedef struct dt_iop_exposure_params_v7_t
174+ {
175+ dt_iop_exposure_mode_t mode ;
176+ float black ;
177+ float exposure ;
178+ float deflicker_percentile ;
179+ float deflicker_target_level ;
180+ gboolean compensate_exposure_bias ;
181+ gboolean compensate_hilite_pres ;
182+ } dt_iop_exposure_params_v7_t ;
183+
171184 if (old_version == 2 )
172185 {
173186 typedef struct dt_iop_exposure_params_v2_t
@@ -272,6 +285,24 @@ int legacy_params(dt_iop_module_t *self,
272285 * new_version = 6 ;
273286 return 0 ;
274287 }
288+ if (old_version == 6 )
289+ {
290+ const dt_iop_exposure_params_v6_t * o = (dt_iop_exposure_params_v6_t * )old_params ;
291+ dt_iop_exposure_params_v7_t * n = malloc (sizeof (dt_iop_exposure_params_v7_t ));
292+
293+ n -> mode = o -> mode ;
294+ n -> black = o -> black ;
295+ n -> exposure = o -> exposure ;
296+ n -> deflicker_percentile = o -> deflicker_percentile ;
297+ n -> deflicker_target_level = o -> deflicker_target_level ;
298+ n -> compensate_exposure_bias = o -> compensate_exposure_bias ;
299+ n -> compensate_hilite_pres = FALSE; // module did not compensate h.p. before version 7
300+
301+ * new_params = n ;
302+ * new_params_size = sizeof (dt_iop_exposure_params_v7_t );
303+ * new_version = 7 ;
304+ return 0 ;
305+ }
275306 return 1 ;
276307}
277308
@@ -287,7 +318,8 @@ void init_presets(dt_iop_module_so_t *self)
287318 .exposure = 0.0f ,
288319 .deflicker_percentile = 50.0f ,
289320 .deflicker_target_level = -4.0f ,
290- .compensate_exposure_bias = FALSE},
321+ .compensate_exposure_bias = FALSE,
322+ .compensate_hilite_pres = FALSE },
291323 sizeof (dt_iop_exposure_params_t ), TRUE, DEVELOP_BLEND_CS_RGB_DISPLAY );
292324
293325 const gboolean is_scene_referred = dt_is_scene_referred ();
@@ -333,6 +365,7 @@ void reload_defaults(dt_iop_module_t *self)
333365 d -> black = 0.0f ;
334366 d -> compensate_exposure_bias = FALSE;
335367 }
368+ d -> compensate_hilite_pres = TRUE;
336369}
337370
338371static void _deflicker_prepare_histogram (dt_iop_module_t * self ,
@@ -545,6 +578,26 @@ static float _get_exposure_bias(const dt_iop_module_t *self)
545578 return 0.0f ;
546579}
547580
581+ static float _get_highlight_bias (const dt_iop_module_t * self )
582+ {
583+ float bias = 0.0f ;
584+
585+ // Nikon: Exif.Nikon3.Colorspace==4 --> +2 EV
586+ // Fuji: Exif.Fujifilm.DevelopmentDynamicRange
587+ // 100 --> no comp
588+ // 200 --> +1 EV
589+ // 400 --> +2 EV
590+
591+ if (self -> dev && self -> dev -> image_storage .exif_highlight_preservation > 0.0f )
592+ bias = self -> dev -> image_storage .exif_highlight_preservation ;
593+
594+ // sanity checks, don't trust exif tags too much
595+ if (bias != DT_EXIF_TAG_UNINITIALIZED )
596+ return CLAMP (bias , -1.0f , 4.0f );
597+ else
598+ return 0.0f ;
599+ }
600+
548601
549602void commit_params (dt_iop_module_t * self ,
550603 dt_iop_params_t * p1 ,
@@ -564,6 +617,12 @@ void commit_params(dt_iop_module_t *self,
564617 if (p -> compensate_exposure_bias )
565618 d -> params .exposure -= _get_exposure_bias (self );
566619
620+ // If highlight preservation compensation has been required, add it on top of
621+ // the previous compensation values
622+ // d->params.compensate_hilite_pres = p->compensate_hilite_pres;
623+ if (p -> compensate_hilite_pres )
624+ d -> params .exposure += _get_highlight_bias (self );
625+
567626 d -> deflicker = 0 ;
568627
569628 if (p -> mode == EXPOSURE_MODE_DEFLICKER
@@ -579,7 +638,7 @@ void init_pipe(dt_iop_module_t *self,
579638 dt_dev_pixelpipe_t * pipe ,
580639 dt_dev_pixelpipe_iop_t * piece )
581640{
582- piece -> data = malloc ( sizeof (dt_iop_exposure_data_t ));
641+ piece -> data = calloc ( 1 , sizeof (dt_iop_exposure_data_t ));
583642}
584643
585644void cleanup_pipe (dt_iop_module_t * self ,
@@ -626,6 +685,18 @@ void gui_update(dt_iop_module_t *self)
626685 PANGO_ELLIPSIZE_MIDDLE );
627686 g_free (label );
628687
688+ const float hlbias = _get_highlight_bias (self );
689+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g -> compensate_hilite_preserv ),
690+ p -> compensate_hilite_pres );
691+ /* xgettext:no-c-format */
692+ label = g_strdup_printf (_ ("higlight preservation mode (%.1f EV)" ), hlbias );
693+ gtk_button_set_label (GTK_BUTTON (g -> compensate_hilite_preserv ), label );
694+ gtk_label_set_ellipsize
695+ (GTK_LABEL (gtk_bin_get_child (GTK_BIN (g -> compensate_hilite_preserv ))),
696+ PANGO_ELLIPSIZE_MIDDLE );
697+ g_free (label );
698+ gtk_widget_set_sensitive (GTK_WIDGET (g -> compensate_hilite_preserv ), hlbias > 0.0f );
699+
629700 g -> spot_RGB [0 ] = 0.f ;
630701 g -> spot_RGB [1 ] = 0.f ;
631702 g -> spot_RGB [2 ] = 0.f ;
@@ -669,7 +740,7 @@ void gui_update(dt_iop_module_t *self)
669740void init_global (dt_iop_module_so_t * self )
670741{
671742 const int program = 2 ; // from programs.conf: basic.cl
672- dt_iop_exposure_global_data_t * gd = malloc ( sizeof (dt_iop_exposure_global_data_t ));
743+ dt_iop_exposure_global_data_t * gd = calloc ( 1 , sizeof (dt_iop_exposure_global_data_t ));
673744 self -> data = gd ;
674745 gd -> kernel_exposure = dt_opencl_create_kernel (program , "exposure" );
675746}
@@ -813,6 +884,10 @@ static void _auto_set_exposure(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe)
813884 if (p -> compensate_exposure_bias )
814885 expo -= _get_exposure_bias (self );
815886
887+ // If the highlight preservation mode is on, we need to add it to the user param
888+ if (p -> compensate_hilite_pres )
889+ expo += _get_highlight_bias (self );
890+
816891 const float white = exposure2white (- expo );
817892
818893 // apply the exposure compensation
@@ -855,6 +930,10 @@ static void _auto_set_exposure(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe)
855930 if (p -> compensate_exposure_bias )
856931 expo -= _get_exposure_bias (self );
857932
933+ // If the highlight preservation mode is on, we need to add it to the user param
934+ if (p -> compensate_hilite_pres )
935+ expo += _get_highlight_bias (self );
936+
858937 white = exposure2white (- expo );
859938 _exposure_set_white (self , white );
860939 }
@@ -1097,6 +1176,15 @@ void gui_init(dt_iop_module_t *self)
10971176 _ ("automatically remove the camera exposure bias\n"
10981177 "this is useful if you exposed the image to the right." ));
10991178
1179+ g -> compensate_hilite_preserv = dt_bauhaus_toggle_from_params
1180+ (self , "compensate_hilite_pres" );
1181+ gtk_widget_set_tooltip_text (g -> compensate_hilite_preserv ,
1182+ _ ("remove the camera's hidden exposure bias in\n"
1183+ "HDR / highlight preservation / dynamic range / HLG tone mode.\n"
1184+ "\n"
1185+ "when enabled, tone mapping (e.g. sigmoid) is required to\n"
1186+ "avoid blown-out highlights." ));
1187+
11001188 g -> exposure = dt_color_picker_new (self , DT_COLOR_PICKER_AREA ,
11011189 dt_bauhaus_slider_from_params (self , N_ ("exposure" )));
11021190 gtk_widget_set_tooltip_text (g -> exposure , _ ("adjust the exposure correction" ));
0 commit comments