@@ -76,6 +76,7 @@ dt_iop_colorspace_type_t default_colorspace(dt_iop_module_t *self,
7676}
7777
7878static const float _epsilon = 1E-6f ;
79+ static const float _default_gamma = 2.2f ;
7980
8081typedef enum dt_iop_agx_base_primaries_t
8182{
@@ -906,7 +907,28 @@ static tone_mapping_params_t _calculate_tone_mapping_params(const dt_iop_agx_par
906907 _adjust_pivot (p , & tone_mapping_params );
907908
908909 // avoid range altering slope - 16.5 EV is the default AgX range; keep the meaning of slope
909- tone_mapping_params .slope = p -> curve_contrast_around_pivot * (tone_mapping_params .range_in_ev / 16.5f );
910+ const float range_adjusted_slope = p -> curve_contrast_around_pivot * (tone_mapping_params .range_in_ev / 16.5f );
911+
912+ // compensate contrast relative to gamma 2.2 to keep contrast around the pivot constant
913+ const float gamma = tone_mapping_params .curve_gamma ;
914+ const float pivot_y = tone_mapping_params .pivot_y ;
915+
916+ // We want to maintain the contrast after linearisation, so we need to apply
917+ // the chain rule (f(g(x)' = f'(g(x)) * g'(x))
918+ // to find the derivative of linearisation(curve(x)) = curve(x)^gamma.
919+ // By definition, the derivative of the curve g'(pivot_x)) = the slope;
920+ // also, curve(pivot_x) = pivot_y, so we need the derivative of the
921+ // power function at that point: f'(pivot_y).
922+ // We want to find gamma_compensated_slope to keep the overall derivative constant:
923+ // gamma_compensated_slope * [gamma * pivot_y^(current_gamma-1)] =
924+ // range_adjusted_slope * [_default_gamma * pivot_y^(_default_gamma-1)],
925+ // and thus gamma_compensated_slope = range_adjusted_slope *
926+ // [_default_gamma * pivot_y^(_default_gamma-1)] / [gamma * pivot_y^(current_gamma-1)]
927+ const float derivative_at_current_gamma = gamma * powf (fmaxf (_epsilon , pivot_y ), gamma - 1.0f );
928+ const float derivative_at_default_gamma = _default_gamma * powf (fmaxf (_epsilon , pivot_y ), _default_gamma - 1.0f );
929+ const float compensation_factor = derivative_at_current_gamma / derivative_at_default_gamma ;
930+
931+ tone_mapping_params .slope = range_adjusted_slope / compensation_factor ;
910932
911933 // toe
912934 tone_mapping_params .target_black =
@@ -1460,7 +1482,7 @@ static gboolean _agx_draw_curve(GtkWidget *widget, cairo_t *crf, const dt_iop_mo
14601482 if (ev % 5 == 0 || ev == ceilf (min_ev ) || ev == floorf (max_ev ))
14611483 {
14621484 cairo_save (cr );
1463- cairo_identity_matrix (cr ); // eeset transformations for text
1485+ cairo_identity_matrix (cr ); // reset transformations for text
14641486 set_color (cr , darktable .bauhaus -> graph_fg );
14651487 snprintf (text , sizeof (text ), "%d" , ev );
14661488 pango_layout_set_text (layout , text , -1 );
@@ -1580,7 +1602,7 @@ void gui_changed(dt_iop_module_t *self, GtkWidget *widget, void *previous)
15801602 {
15811603 darktable .gui -> reset ++ ;
15821604 const float prev = * (float * )previous ;
1583- const float ratio = (p -> security_factor - prev ) / (prev + 100 .f );
1605+ const float ratio = (p -> security_factor - prev ) / (prev + 1 .f );
15841606
15851607 p -> range_black_relative_exposure *= (1.f + ratio );
15861608 p -> range_white_relative_exposure *= (1.f + ratio );
@@ -1808,15 +1830,15 @@ static GtkWidget* _create_advanced_box(dt_iop_module_t *self, dt_iop_agx_gui_dat
18081830 _ ("tries to make sure the curve always remains S-shaped,\n"
18091831 "given that contrast is high enough, so toe and shoulder\n"
18101832 "controls remain effective.\n"
1811- "affects overall contrast, you may have to counteract it with the contrast slider." ));
1833+ "affects overall contrast, you may have to counteract it with the contrast slider, or with toe / shoulder controls ." ));
18121834
18131835 slider = dt_bauhaus_slider_from_params (section , "curve_gamma" );
18141836 g -> curve_gamma = slider ;
18151837 dt_bauhaus_slider_set_soft_range (slider , 1.f , 5.f );
18161838 gtk_widget_set_tooltip_text (slider ,
18171839 _ ("shifts representation (but not output brightness) of pivot\n"
18181840 "along the y axis of the curve.\n"
1819- "affects overall contrast, you may have to counteract it with the contrast slider." ));
1841+ "affects overall contrast, you may have to counteract it with the contrast slider, or with toe / shoulder controls ." ));
18201842
18211843 self -> widget = parent ;
18221844
@@ -2246,7 +2268,7 @@ static void _set_neutral_params(dt_iop_agx_params_t *p)
22462268 p -> curve_target_display_black_ratio = 0.f ;
22472269 p -> curve_target_display_white_ratio = 1.f ;
22482270 p -> auto_gamma = FALSE;
2249- p -> curve_gamma = 2.2f ;
2271+ p -> curve_gamma = _default_gamma ;
22502272 p -> curve_pivot_x_shift_ratio = 0.f ;
22512273 p -> curve_pivot_y_ratio = 0.18f ;
22522274
0 commit comments