146#define UI_SAMPLES 256
147#define CONTRAST_FULCRUM exp2f(-4.0f)
148#define MIN_FLOAT exp2f(-16.0f)
157#define LUT_RESOLUTION 10000
170 -4.0f, -3.0f, -2.0f, -1.0f, 0.0f};
326 return _(
"tone e_qualizer");
331 return _(
"tone curve|tone mapping|relight|background light|shadows highlights");
337 return dt_iop_set_description(self, _(
"relight the scene as if the lighting was done directly on the scene"),
338 _(
"corrective and creative"),
339 _(
"linear, RGB, scene-referred"),
340 _(
"quasi-linear, RGB"),
341 _(
"quasi-linear, RGB, scene-referred"));
368 const int new_version)
370 if(old_version == 1 && new_version == 2)
372 typedef struct dt_iop_toneequalizer_params_v1_t
374 float noise, ultra_deep_blacks, deep_blacks, blacks, shadows, midtones, highlights, whites, speculars;
379 } dt_iop_toneequalizer_params_v1_t;
381 dt_iop_toneequalizer_params_v1_t *o = (dt_iop_toneequalizer_params_v1_t *)old_params;
389 n->ultra_deep_blacks = o->ultra_deep_blacks;
390 n->deep_blacks = o->deep_blacks;
391 n->blacks = o->blacks;
392 n->shadows = o->shadows;
393 n->midtones = o->midtones;
394 n->highlights = o->highlights;
395 n->whites = o->whites;
396 n->speculars = o->speculars;
398 n->blending = o->blending;
399 n->feathering = o->feathering;
400 n->contrast_boost = o->contrast_boost;
401 n->exposure_boost = o->exposure_boost;
403 n->details = o->details;
404 n->iterations = o->iterations;
405 n->method = o->method;
408 n->quantization = 0.01f;
409 n->smoothing = sqrtf(2.0f);
421 p->ultra_deep_blacks = 5.f / 3.f * step;
422 p->deep_blacks = 5.f / 3.f * step;
426 p->highlights = -5.f / 3.f * step;
427 p->whites = -5.f / 3.f * step;
428 p->speculars = -step;
436 p->noise = -15.f / 9.f * step;
437 p->ultra_deep_blacks = -14.f / 9.f * step;
438 p->deep_blacks = -12.f / 9.f * step;
439 p->blacks = -8.f / 9.f * step;
441 p->midtones = 8.f / 9.f * step;
442 p->highlights = 12.f / 9.f * step;
443 p->whites = 14.f / 9.f * step;
444 p->speculars = 15.f / 9.f * step;
450 memset(&
p, 0,
sizeof(
p));
453 p.contrast_boost = 0.0f;
455 p.exposure_boost = -0.5f;
458 p.smoothing = sqrtf(2.0f);
459 p.quantization = 0.0f;
462 p.noise =
p.ultra_deep_blacks =
p.deep_blacks =
p.blacks =
p.shadows =
p.midtones =
p.highlights =
p.whites =
p. speculars = 0.0f;
475 p.quantization = 0.0f;
476 p.exposure_boost = 0.0f;
477 p.contrast_boost = 0.0f;
482 p.feathering = 10.0f;
489 p.exposure_boost = -1.57f;
490 p.contrast_boost = 0.0f;
492 p.feathering = 50.0f;
494 p.quantization = 0.0f;
498 p.feathering = 20.0f;
503 p.feathering = 500.0f;
515 p.feathering = 500.0f;
527 p.feathering = 500.0f;
550 p.quantization = 0.0f;
551 p.exposure_boost = -0.5f;
552 p.contrast_boost = 0.0f;
555 p.ultra_deep_blacks = 0.15f;
556 p.deep_blacks = 0.6f;
592 g->max_histogram = 1;
593 g->luminance_valid =
FALSE;
594 g->histogram_valid = 0;
597 g->thumb_preview_buf_width = 0;
598 g->thumb_preview_buf_height = 0;
599 preview_entry =
g->thumb_preview_entry;
600 g->thumb_preview_entry = NULL;
614 const double position_self = self->
iop_order;
617 if(position_self < position_min && self->enabled)
619 dt_control_log(_(
"tone equalizer needs to be after distortion modules in the pipeline - disabled"));
620 fprintf(stdout,
"tone equalizer needs to be after distortion modules in the pipeline - disabled\n");
630 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
off), self->
enabled);
642 { { 0.076555024f, 0.124401914f, 0.076555024f },
643 { 0.124401914f, 0.196172249f, 0.124401914f },
644 { 0.076555024f, 0.124401914f, 0.076555024f } };
648 const size_t x,
const size_t y)
666 for(
int i = 0;
i < 3; ++
i)
668 const size_t y_i = y_abs[
i];
682 for(
int i = 0;
i < 3; ++
i)
684 const size_t y_i = y_abs[
i];
711static inline
__attribute__((always_inline))
float gaussian_func(const
float radius, const
float denominator)
717 return expf(- radius * radius / denominator);
720#define DT_TONEEQ_USE_LUT TRUE
728 float *
const restrict
out,
733 const size_t num_elem = (size_t)roi_in->
width * roi_in->
height;
734 const int min_ev = -8;
735 const int max_ev = 0;
736 const float* restrict
lut =
d->correction_lut;
738 for(
size_t k = 0;
k < num_elem; ++
k)
742 const float correction =
lut[(unsigned)roundf((exposure - min_ev) *
LUT_RESOLUTION)];
743 const size_t idx =
k *
ch;
744 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in + idx);
745 const dt_aligned_pixel_simd_t correction_v = { correction, correction, correction, 1.0f };
746 dt_store_simd_nontemporal(
out + idx, pix_in * correction_v);
758 float *
const restrict
out,
763 const size_t num_elem = roi_in->
width * roi_in->
height;
764 const float *
const restrict factors =
d->factors;
765 const float sigma =
d->smoothing;
766 const float gauss_denom = gaussian_denom(
sigma);
768 for(
size_t k = 0;
k < num_elem; ++
k)
778 result += gaussian_func(exposure - centers_ops[
i], gauss_denom) * factors[
i];
781 const float correction =
fast_clamp(result, 0.25f, 4.0f);
782 const size_t idx =
k *
ch;
783 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in + idx);
784 const dt_aligned_pixel_simd_t correction_v = { correction, correction, correction, 1.0f };
785 dt_store_simd_nontemporal(
out + idx, pix_in * correction_v);
792 const float *
const restrict factors,
798 const float gauss_denom = gaussian_denom(
sigma);
799 const float expo =
fast_clamp(exposure, -8.0f, 0.0f);
802 result += gaussian_func(expo - centers_ops[
i], gauss_denom) * factors[
i];
885 float *
const restrict
out,
890 const size_t offset_x = (roi_in->
x < roi_out->
x) ? -roi_in->
x + roi_out->
x : 0;
891 const size_t offset_y = (roi_in->
y < roi_out->
y) ? -roi_in->
y + roi_out->
y : 0;
896 const size_t in_width = roi_in->
width;
900 for(
size_t i = 0 ;
i < out_height; ++
i)
901 for(
size_t j = 0; j < out_width; ++j)
905 const float intensity = sqrtf(fminf(fmaxf(
luminance[(
i + offset_y) * in_width + (j + offset_x)] - 0.00390625f, 0.f) / 0.99609375f, 1.f));
906 const size_t index = (
i * out_width + j) *
ch;
907 dt_aligned_pixel_simd_t intensity_v =
dt_simd_set1(intensity);
912 const size_t in_index = ((
i + offset_y) * in_width + (j + offset_x)) *
ch;
913 intensity_v[3] = in[in_index + 3];
916 dt_store_simd_nontemporal(
out + index, intensity_v);
934 gboolean created_luminance_entry =
FALSE;
940 dt_control_log(_(
"tone equalizer in/out buffer are ill-aligned, please report the bug to the developers"));
941 fprintf(stdout,
"tone equalizer in/out buffer are ill-aligned, please report the bug to the developers\n");
945 const size_t width = roi_in->width;
946 const size_t height = roi_in->height;
951 const int position = self->iop_order;
956 if(roi_in->width < roi_out->width || roi_in->height < roi_out->height)
return 0;
957 if(!sanity_check(self))
964 if(self->dev->gui_attached)
974 g->thumb_preview_buf_width = 0;
975 g->thumb_preview_buf_height = 0;
976 g->luminance_valid =
FALSE;
977 g->histogram_valid =
FALSE;
978 preview_entry =
g->thumb_preview_entry;
979 g->thumb_preview_entry = NULL;
987 if(self->dev->gui_attached)
1002 void *cache_data = NULL;
1003 static const char cache_tag[] =
"toneequal:luminance";
1004 luminance_hash =
dt_hash(piece->global_hash, cache_tag,
sizeof(cache_tag));
1007 num_elem *
sizeof(
float),
"toneequal luminance",
1008 pipe->type,
TRUE, &cache_data,
1015 if(created_luminance_entry)
1022 if(created_luminance_entry)
1065 if(preview_output && self->dev->gui_attached && !
IS_NULL_PTR(
g) && luminance_entry)
1068 gboolean keep_process_ref =
FALSE;
1075 if(
g->thumb_preview_entry != luminance_entry ||
g->thumb_preview_hash != luminance_hash)
1077 old_entry =
g->thumb_preview_entry;
1078 g->thumb_preview_entry = luminance_entry;
1079 g->thumb_preview_hash = luminance_hash;
1081 g->thumb_preview_buf_width =
width;
1082 g->thumb_preview_buf_height =
height;
1083 g->luminance_valid =
TRUE;
1084 g->histogram_valid =
FALSE;
1085 keep_process_ref =
TRUE;
1092 if(!keep_process_ref)
1095 else if(luminance_entry)
1108 const void *
const restrict ivoid,
void *
const restrict
ovoid)
1112 return toneeq_process(self, pipe, piece, ivoid,
ovoid, roi_in, roi_out);
1128 const int radius = (int)((diameter - 1.0f) / ( 2.0f));
1175 const float gauss_denom = gaussian_denom(
sigma);
1176 const int min_ev = -8;
1183 float result = 0.0f;
1185 result += gaussian_func(exposure - centers_ops[
i], gauss_denom) * factors[
i];
1196 factors[0] =
p->noise;
1197 factors[1] =
p->ultra_deep_blacks;
1198 factors[2] =
p->deep_blacks;
1199 factors[3] =
p->blacks;
1200 factors[4] =
p->shadows;
1201 factors[5] =
p->midtones;
1202 factors[6] =
p->highlights;
1203 factors[7] =
p->whites;
1204 factors[8] =
p->speculars;
1218 factors[c] = exp2f(factors[c]);
1237 if(isnan(
out[
i]) ||
out[
i] < 0.25f ||
out[
i] > 4.0f) valid = 0;
1249 const int valid = 1;
1252 out[
i] = log2f(in[
i]);
1260 p->noise = factors[0];
1261 p->ultra_deep_blacks = factors[1];
1262 p->deep_blacks = factors[2];
1263 p->blacks = factors[3];
1264 p->shadows = factors[4];
1265 p->midtones = factors[5];
1266 p->highlights = factors[6];
1267 p->whites = factors[7];
1268 p->speculars = factors[8];
1287 g->max_histogram = 1;
1289 g->sigma = sqrtf(2.0f);
1292 g->interpolation_valid =
FALSE;
1293 g->luminance_valid =
FALSE;
1294 g->histogram_valid =
FALSE;
1297 g->user_param_valid =
FALSE;
1298 g->factors_valid =
TRUE;
1300 g->valid_nodes_x =
FALSE;
1301 g->valid_nodes_y =
FALSE;
1302 g->area_cursor_valid =
FALSE;
1303 g->area_dragging =
FALSE;
1306 g->thumb_preview_entry = NULL;
1307 g->thumb_preview_buf_width = 0;
1308 g->thumb_preview_buf_height = 0;
1333 static const char cache_tag[] =
"toneequal:luminance";
1344 const float gauss_denom = gaussian_denom(
sigma);
1345 __OMP_SIMD__(aligned(
A, centers_ops, centers_params:64) collapse(2))
1348 A[
i *
PIXEL_CHAN + j] = gaussian_func(centers_params[
i] - centers_ops[j], gauss_denom);
1355 const size_t num_elem,
1357 float *first_decile,
float *last_decile)
1360 memset(histogram, 0,
sizeof(
int) *
UI_SAMPLES);
1363 #define TEMP_SAMPLES 2 * UI_SAMPLES
1369 for(
size_t k = 0;
k < num_elem;
k++)
1373 temp_hist[index] += 1;
1376 const int first = (int)((
float)num_elem * 0.05f);
1377 const int last = (int)((
float)num_elem * (1.0f - 0.95f));
1386 const size_t prev_population = population;
1387 population += temp_hist[
k];
1388 if(prev_population < first && first <= population)
1397 const size_t prev_population = population;
1398 population += temp_hist[
k];
1399 if(prev_population < last && last <= population)
1407 *first_decile = 16.0 * (float)first_pos / (
float)(
TEMP_SAMPLES - 1) - 10.0;
1408 *last_decile = 16.0 * (float)last_pos / (
float)(
TEMP_SAMPLES - 1) - 10.0;
1414 float EV = 16.0 * (float)
k / (
float)(
TEMP_SAMPLES - 1) - 10.0;
1416 histogram[
i] += temp_hist[
k];
1419 *max_histogram = histogram[
i] > *max_histogram ? histogram[
i] : *max_histogram;
1432 gboolean needs_histogram =
FALSE;
1438 if(!
g->histogram_valid &&
g->luminance_valid &&
g->thumb_preview_entry)
1440 preview_entry =
g->thumb_preview_entry;
1441 width =
g->thumb_preview_buf_width;
1442 height =
g->thumb_preview_buf_height;
1443 preview_hash =
g->thumb_preview_hash;
1445 needs_histogram =
TRUE;
1457 int max_histogram = 1;
1458 float first_decile = 0.0f;
1459 float last_decile = 0.0f;
1475 if(
g->thumb_preview_entry == preview_entry &&
g->thumb_preview_hash == preview_hash && !
g->histogram_valid)
1477 memcpy(
g->histogram, histogram,
sizeof(histogram));
1478 g->max_histogram = max_histogram;
1479 g->histogram_first_decile = first_decile;
1480 g->histogram_last_decile = last_decile;
1481 g->histogram_average = (first_decile + last_decile) / 2.0f;
1482 g->histogram_valid =
TRUE;
1498 float *
const restrict LUT =
g->gui_lut;
1499 const float *
const restrict factors =
g->factors;
1500 const float sigma =
g->sigma;
1506 const float x = (8.0f * (((float)
k) / ((float)(
UI_SAMPLES - 1)))) - 8.0f;
1520 gboolean valid =
TRUE;
1522 if(!
g->interpolation_valid)
1525 g->interpolation_valid =
TRUE;
1526 g->factors_valid =
FALSE;
1529 if(!
g->user_param_valid)
1534 g->user_param_valid =
TRUE;
1535 g->factors_valid =
FALSE;
1538 if(!
g->factors_valid &&
g->user_param_valid)
1549 g->factors_valid =
TRUE;
1554 if(!
g->lut_valid &&
g->factors_valid)
1557 g->lut_valid =
TRUE;
1587 d->method =
p->method;
1588 d->details =
p->details;
1589 d->iterations =
p->iterations;
1590 d->smoothing =
p->smoothing;
1591 d->quantization =
p->quantization;
1594 d->blending =
p->blending / 100.0f;
1598 d->feathering = 1.f / (
p->feathering);
1601 d->contrast_boost = exp2f(
p->contrast_boost);
1602 d->exposure_boost = exp2f(
p->exposure_boost);
1612 if(
g->sigma !=
p->smoothing)
g->interpolation_valid =
FALSE;
1613 g->sigma =
p->smoothing;
1614 g->user_param_valid =
FALSE;
1661 gtk_widget_set_visible(
g->blending,
FALSE);
1662 gtk_widget_set_visible(
g->feathering,
FALSE);
1663 gtk_widget_set_visible(
g->iterations,
FALSE);
1664 gtk_widget_set_visible(
g->contrast_boost,
FALSE);
1665 gtk_widget_set_visible(
g->quantization,
FALSE);
1672 gtk_widget_set_visible(
g->blending,
TRUE);
1673 gtk_widget_set_visible(
g->feathering,
TRUE);
1674 gtk_widget_set_visible(
g->iterations,
TRUE);
1675 gtk_widget_set_visible(
g->contrast_boost,
FALSE);
1676 gtk_widget_set_visible(
g->quantization,
TRUE);
1683 gtk_widget_set_visible(
g->blending,
TRUE);
1684 gtk_widget_set_visible(
g->feathering,
TRUE);
1685 gtk_widget_set_visible(
g->iterations,
TRUE);
1686 gtk_widget_set_visible(
g->contrast_boost,
TRUE);
1687 gtk_widget_set_visible(
g->quantization,
TRUE);
1719 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->show_luminance_mask),
g->mask_display);
1725 if(w ==
g->method ||
1727 w ==
g->feathering ||
1728 w ==
g->iterations ||
1729 w ==
g->quantization)
1733 else if (w ==
g->details)
1738 else if (w ==
g->contrast_boost || w ==
g->exposure_boost)
1759 if(!valid)
dt_control_log(_(
"the interpolation is unstable, decrease the curve smoothing"));
1763 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
1775 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
off),
TRUE);
1783 g->mask_display = !
g->mask_display;
1789 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->show_luminance_mask),
g->mask_display);
1841 _(
"scroll over image to change tone exposure\n"
1842 "shift+scroll for large steps; "
1843 "ctrl+scroll for small steps"));
1847 else if(!
g->cursor_valid)
1875 const int fail = !sanity_check(self);
1881 g->area_active_node = -1;
1883 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
1891 if(wd < 1 || ht < 1)
return 0;
1893 float pzxpy[2] = { (float)
x, (
float)y };
1897 const int x_pointer = pzxpy[0];
1898 const int y_pointer = pzxpy[1];
1901 if(x_pointer >= 0 && x_pointer < wd && y_pointer >= 0 && y_pointer < ht)
1903 g->cursor_valid =
TRUE;
1904 g->cursor_pos_x = x_pointer;
1905 g->cursor_pos_y = y_pointer;
1910 g->cursor_pos_x = 0;
1911 g->cursor_pos_y = 0;
1918 size_t preview_width = 0;
1919 size_t preview_height = 0;
1924 if(
g->luminance_valid && !
IS_NULL_PTR(
g->thumb_preview_entry))
1926 preview_entry =
g->thumb_preview_entry;
1927 preview_width =
g->thumb_preview_buf_width;
1928 preview_height =
g->thumb_preview_buf_height;
1933 if(!
IS_NULL_PTR(preview_entry) && preview_width > 0 && preview_height > 0)
1937 const float cursor_exposure
1939 (
size_t)x_pointer, (
size_t)y_pointer))
1943 if(!isnan(cursor_exposure))
1945 g->cursor_exposure = cursor_exposure;
1966 g->area_active_node = -1;
1971 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
1986 const float std = gaussian_denom(blending_sigma);
1987 if(
g->user_param_valid)
1990 g->temp_user_params[
i] *= exp2f(gaussian_func(centers_params[
i] - control_exposure, std) * exposure_offset);
1996 if(
g->user_param_valid)
1998 if(!
g->user_param_valid)
dt_control_log(_(
"the interpolation is unstable, decrease the curve smoothing"));
2001 if(
g->user_param_valid)
2003 if(!
g->user_param_valid)
dt_control_log(_(
"some parameters are out-of-bounds"));
2005 const int commit =
g->user_param_valid;
2023 g->user_param_valid = 1;
2036 if(!sanity_check(self))
return 0;
2044 if(self->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
off), 1);
2047 const int fail = (!
g->cursor_valid || !
g->interpolation_valid || !
g->user_param_valid || dev->
pipe->
processing || !self->
expanded);
2052 size_t preview_width = 0;
2053 size_t preview_height = 0;
2060 if(
g->luminance_valid && !
IS_NULL_PTR(
g->thumb_preview_entry))
2062 preview_entry =
g->thumb_preview_entry;
2063 preview_width =
g->thumb_preview_buf_width;
2064 preview_height =
g->thumb_preview_buf_height;
2065 cursor_x =
g->cursor_pos_x;
2066 cursor_y =
g->cursor_pos_y;
2071 if(
IS_NULL_PTR(preview_entry) || preview_width == 0 || preview_height == 0)
2078 if(!
IS_NULL_PTR(preview_entry) && preview_width > 0 && preview_height > 0)
2082 const float cursor_exposure
2084 (
size_t)cursor_x, (
size_t)cursor_y))
2088 if(!isnan(cursor_exposure))
2090 g->cursor_exposure = cursor_exposure;
2098 const float increment = (up) ? +1.0f : -1.0f;
2108 const float offset = step * ((float)increment);
2113 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
2134void cairo_draw_hatches(cairo_t *cr,
double center[2],
double span[2],
int instances,
double line_width,
double shade)
2140 double C0[2] = { center[0] - span[0], center[1] - span[1] };
2141 double C2[2] = { center[0] + span[0], center[1] + span[1] };
2143 double delta[2] = { 2.0 * span[0] / (
double)instances,
2144 2.0 * span[1] / (
double)instances };
2146 cairo_set_line_width(cr, line_width);
2147 cairo_set_source_rgb(cr, shade, shade, shade);
2149 for(
int i = -instances / 2 - 1;
i <= instances / 2 + 1;
i++)
2151 cairo_move_to(cr, C0[0] + (
double)
i *
delta[0], C0[1]);
2152 cairo_line_to(cr, C2[0] + (
double)
i *
delta[0], C2[1]);
2160 const float gamma = 1.0f / 2.2f;
2161 const float shade = powf(
luminance, gamma);
2162 cairo_set_source_rgba(cr, shade, shade, shade, alpha);
2166static void draw_exposure_cursor(cairo_t *cr,
const double pointerx,
const double pointery,
const double radius,
const float luminance,
const float zoom_scale,
const int instances,
const float alpha)
2171 const double radius_z = radius / zoom_scale;
2174 cairo_arc(cr, pointerx, pointery, radius_z, 0, 2 *
M_PI);
2175 cairo_fill_preserve(cr);
2182 double pointer_coord[2] = { pointerx, pointery };
2183 double span[2] = { radius_z, radius_z };
2194 const float contrast = 1.0f;
2196 if(exposure > -2.5f)
2197 shade = (fminf(exposure * contrast, 0.0f) - 2.5f);
2199 shade = (fmaxf(exposure / contrast, -5.0f) + 2.5f);
2206 int32_t pointerx, int32_t pointery)
2217 const int fail = (!
g->cursor_valid || !
g->interpolation_valid || dev->
pipe->
processing
2218 || !sanity_check(self) || !self->
expanded);
2225 const float x_pointer =
g->cursor_pos_x;
2226 const float y_pointer =
g->cursor_pos_y;
2228 size_t preview_width = 0;
2229 size_t preview_height = 0;
2233 float exposure_in = 0.0f;
2234 float luminance_in = 0.0f;
2235 float correction = 0.0f;
2236 float exposure_out = 0.0f;
2237 float luminance_out = 0.0f;
2243 if(
g->luminance_valid && !
IS_NULL_PTR(
g->thumb_preview_entry))
2245 preview_entry =
g->thumb_preview_entry;
2246 preview_width =
g->thumb_preview_buf_width;
2247 preview_height =
g->thumb_preview_buf_height;
2255 if(!
IS_NULL_PTR(preview_entry) && preview_width > 0 && preview_height > 0)
2262 (
size_t)x_pointer, (
size_t)y_pointer));
2263 luminance_in = exp2f(exposure_in);
2265 exposure_out = exposure_in + correction;
2266 luminance_out = exp2f(exposure_out);
2275 if(!isnan(exposure_in))
2277 g->cursor_exposure = exposure_in;
2284 if(isnan(correction) || isnan(exposure_in))
return;
2291 const double outer_radius = 16.;
2292 const double inner_radius = outer_radius / 2.0;
2293 const double setting_offset_x = (outer_radius + 4. *
g->inner_padding) / zoom_scale;
2298 cairo_set_line_width(cr, 2.0 * fill_width);
2299 cairo_move_to(cr, x_pointer - setting_offset_x, y_pointer);
2301 if(correction > 0.0f)
2302 cairo_arc(cr, x_pointer, y_pointer, setting_offset_x,
M_PI,
M_PI + correction *
M_PI / 4.0);
2304 cairo_arc_negative(cr, x_pointer, y_pointer, setting_offset_x,
M_PI,
M_PI + correction *
M_PI / 4.0);
2310 cairo_move_to(cr, x_pointer + (outer_radius + 2. *
g->inner_padding) / zoom_scale, y_pointer);
2311 cairo_line_to(cr, x_pointer + outer_radius / zoom_scale, y_pointer);
2312 cairo_move_to(cr, x_pointer - outer_radius / zoom_scale, y_pointer);
2313 cairo_line_to(cr, x_pointer - setting_offset_x - 4.0 *
g->inner_padding / zoom_scale, y_pointer);
2318 cairo_move_to(cr, x_pointer, y_pointer + setting_offset_x + fill_width);
2319 cairo_line_to(cr, x_pointer, y_pointer + outer_radius / zoom_scale);
2320 cairo_move_to(cr, x_pointer, y_pointer - outer_radius / zoom_scale);
2321 cairo_line_to(cr, x_pointer, y_pointer - setting_offset_x - fill_width);
2326 draw_exposure_cursor(cr, x_pointer, y_pointer, inner_radius, luminance_out, zoom_scale, 3, .9);
2330 PangoLayout *layout;
2335 const int old_size = pango_font_description_get_size(desc);
2336 pango_font_description_set_size (desc, (
int)(old_size / zoom_scale));
2337 layout = pango_cairo_create_layout(cr);
2338 pango_layout_set_font_description(layout, desc);
2342 if(preview_entry && self->
enabled)
2343 snprintf(text,
sizeof(text), _(
"%+.1f EV"), exposure_in);
2345 snprintf(text,
sizeof(text),
"? EV");
2346 pango_layout_set_text(layout, text, -1);
2347 pango_layout_get_pixel_extents(layout, &ink, NULL);
2351 cairo_rectangle(cr, x_pointer + (outer_radius + 2. *
g->inner_padding) / zoom_scale,
2352 y_pointer - ink.y - ink.height / 2.0 -
g->inner_padding / zoom_scale,
2353 ink.width + 2.0 * ink.x + 4. *
g->inner_padding / zoom_scale,
2354 ink.height + 2.0 * ink.y + 2. *
g->inner_padding / zoom_scale);
2359 cairo_move_to(cr, x_pointer + (outer_radius + 4. *
g->inner_padding) / zoom_scale,
2360 y_pointer - ink.y - ink.height / 2.);
2361 pango_cairo_show_layout(cr, layout);
2365 pango_font_description_free(desc);
2366 g_object_unref(layout);
2368 if(preview_entry && self->
enabled)
2371 const float radius_threshold = 0.45f;
2372 g->area_active_node = -1;
2376 const float delta_x = fabsf(
g->cursor_exposure - centers_params[
i]);
2377 if(delta_x < radius_threshold)
2378 g->area_active_node =
i;
2381 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
2393 const gboolean was_mask =
g->mask_display;
2398 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->show_luminance_mask),
FALSE);
2404 gboolean needs_preview_update =
FALSE;
2416 static const char cache_tag[] =
"toneequal:luminance";
2418 void *preview_buf = NULL;
2422 &preview_buf, &preview_entry);
2427 preview_ready =
FALSE;
2433 gboolean keep_new_entry =
FALSE;
2435 if(
g->thumb_preview_entry != preview_entry ||
g->thumb_preview_hash != preview_hash
2437 ||
g->thumb_preview_buf_height != piece->
roi_in.
height || !
g->luminance_valid)
2439 old_entry =
g->thumb_preview_entry;
2440 g->thumb_preview_entry = preview_entry;
2441 g->thumb_preview_hash = preview_hash;
2445 g->luminance_valid =
TRUE;
2446 g->histogram_valid =
FALSE;
2447 keep_new_entry =
TRUE;
2459 g->pending_preview_hash = preview_hash;
2461 needs_preview_update =
TRUE;
2465 needs_preview_update =
TRUE;
2468 if(needs_preview_update)
2472 _(
"scroll over image to change tone exposure\n"
2473 "shift+scroll for large steps; "
2474 "ctrl+scroll for small steps"));
2483 gtk_widget_get_allocation(widget, &
g->allocation);
2485 if(
g->cst) cairo_surface_destroy(
g->cst);
2488 if(
g->cr) cairo_destroy(
g->cr);
2489 g->cr = cairo_create(
g->cst);
2491 if(
g->layout) g_object_unref(
g->layout);
2492 g->layout = pango_cairo_create_layout(
g->cr);
2494 if(
g->desc) pango_font_description_free(
g->desc);
2497 pango_layout_set_font_description(
g->layout,
g->desc);
2499 g->context = gtk_widget_get_style_context(widget);
2504 snprintf(text,
sizeof(text),
"X");
2505 pango_layout_set_text(
g->layout, text, -1);
2506 pango_layout_get_pixel_extents(
g->layout, &
g->ink, NULL);
2507 g->line_height =
g->ink.height;
2510 snprintf(text,
sizeof(text),
"-");
2511 pango_layout_set_text(
g->layout, text, -1);
2512 pango_layout_get_pixel_extents(
g->layout, &
g->ink, NULL);
2513 g->sign_width =
g->ink.width / 2.0;
2518 g->graph_left_space =
g->line_height +
g->inner_padding;
2519 g->graph_width =
g->allocation.width -
g->inset - 2.0 *
g->line_height;
2520 g->graph_height =
g->allocation.height -
g->inset - 2.0 *
g->line_height;
2521 g->gradient_left_limit = 0.0;
2522 g->gradient_right_limit =
g->graph_width;
2523 g->gradient_top_limit =
g->graph_height + 2 *
g->inner_padding;
2524 g->gradient_width =
g->gradient_right_limit -
g->gradient_left_limit;
2525 g->legend_top_limit = -0.5 *
g->line_height - 2.0 *
g->inner_padding;
2526 g->x_label =
g->graph_width +
g->sign_width + 3.0 *
g->inner_padding;
2528 gtk_render_background(
g->context,
g->cr, 0, 0,
g->allocation.width,
g->allocation.height);
2531 cairo_translate(
g->cr,
g->line_height + 2 *
g->inner_padding,
g->line_height + 3 *
g->inner_padding);
2536 float value = -8.0f;
2540 const float xn = (((float)
k) / ((float)(
CHANNELS - 1))) *
g->graph_width -
g->sign_width;
2541 snprintf(text,
sizeof(text),
"%+.0f",
value);
2542 pango_layout_set_text(
g->layout, text, -1);
2543 pango_layout_get_pixel_extents(
g->layout, &
g->ink, NULL);
2544 cairo_move_to(
g->cr, xn - 0.5 *
g->ink.width -
g->ink.x,
2545 g->legend_top_limit - 0.5 *
g->ink.height -
g->ink.y);
2546 pango_cairo_show_layout(
g->cr,
g->layout);
2547 cairo_stroke(
g->cr);
2554 for(
int k = 0;
k < 5;
k++)
2556 const float yn = (
k / 4.0f) *
g->graph_height;
2557 snprintf(text,
sizeof(text),
"%+.0f",
value);
2558 pango_layout_set_text(
g->layout, text, -1);
2559 pango_layout_get_pixel_extents(
g->layout, &
g->ink, NULL);
2560 cairo_move_to(
g->cr,
g->x_label - 0.5 *
g->ink.width -
g->ink.x,
2561 yn - 0.5 *
g->ink.height -
g->ink.y);
2562 pango_cairo_show_layout(
g->cr,
g->layout);
2563 cairo_stroke(
g->cr);
2570 cairo_pattern_t *grad;
2571 grad = cairo_pattern_create_linear(
g->gradient_left_limit, 0.0,
g->gradient_right_limit, 0.0);
2573 cairo_set_line_width(
g->cr, 0.0);
2574 cairo_rectangle(
g->cr,
g->gradient_left_limit,
g->gradient_top_limit,
g->gradient_width,
g->line_height);
2575 cairo_set_source(
g->cr, grad);
2577 cairo_pattern_destroy(grad);
2581 grad = cairo_pattern_create_linear(0.0,
g->graph_height, 0.0, 0.0);
2583 cairo_set_line_width(
g->cr, 0.0);
2584 cairo_rectangle(
g->cr, -
g->line_height - 2 *
g->inner_padding, 0.0,
g->line_height,
g->graph_height);
2585 cairo_set_source(
g->cr, grad);
2588 cairo_pattern_destroy(grad);
2593 cairo_rectangle(
g->cr, 0, 0,
g->graph_width,
g->graph_height);
2594 cairo_stroke_preserve(
g->cr);
2609 if(!
g->valid_nodes_x &&
g->graph_width > 0)
2612 g->nodes_x[
i] = (((
float)
i) / ((
float)(
CHANNELS - 1))) *
g->graph_width;
2613 g->valid_nodes_x =
TRUE;
2623 if(
g->user_param_valid &&
g->graph_height > 0)
2626 g->nodes_y[
i] = (0.5 - log2f(
g->temp_user_params[
i]) / 4.0) *
g->graph_height;
2627 g->valid_nodes_y =
TRUE;
2645 g->valid_nodes_x =
FALSE;
2646 g->valid_nodes_y =
FALSE;
2654 cairo_rectangle(
g->cr, 0, 0,
g->graph_width,
g->graph_height);
2666 cairo_move_to(
g->cr, 0, 0.5 *
g->graph_height);
2667 cairo_line_to(
g->cr,
g->graph_width, 0.5 *
g->graph_height);
2668 cairo_stroke(
g->cr);
2670 if(
g->histogram_valid && self->
enabled)
2675 cairo_move_to(
g->cr, 0,
g->graph_height);
2680 const float x_temp = (8.0 * (float)
k / (
float)(
UI_SAMPLES - 1)) - 8.0;
2681 const float y_temp = (float)(
g->histogram[
k]) / (float)(
g->max_histogram) * 0.96;
2682 cairo_line_to(
g->cr, (x_temp + 8.0) *
g->graph_width / 8.0,
2683 (1.0 - y_temp) *
g->graph_height );
2685 cairo_line_to(
g->cr,
g->graph_width,
g->graph_height);
2686 cairo_close_path(
g->cr);
2689 if(
g->histogram_last_decile > -0.1f)
2693 cairo_set_source_rgb(
g->cr, 0.75, 0.50, 0.);
2695 2.0 *
g->line_height, 2.0 *
g->line_height, 0, NULL);
2696 cairo_restore(
g->cr);
2699 if(
g->histogram_first_decile < -7.9f)
2703 cairo_set_source_rgb(
g->cr, 0.75, 0.50, 0.);
2705 2.0 *
g->line_height, 2.0 *
g->line_height, 0, NULL);
2706 cairo_restore(
g->cr);
2714 cairo_move_to(
g->cr, 0,
g->gui_lut[0] *
g->graph_height);
2720 const float x_temp = (8.0f * (((float)
k) / ((float)(
UI_SAMPLES - 1)))) - 8.0f;
2721 const float y_temp =
g->gui_lut[
k];
2723 cairo_line_to(
g->cr, (x_temp + 8.0f) *
g->graph_width / 8.0f,
2724 y_temp *
g->graph_height );
2726 cairo_stroke(
g->cr);
2732 if(
g->user_param_valid)
2737 const float xn =
g->nodes_x[
k];
2738 const float yn =
g->nodes_y[
k];
2743 cairo_move_to(
g->cr, xn, 0.5 *
g->graph_height);
2744 cairo_line_to(
g->cr, xn, yn);
2745 cairo_stroke(
g->cr);
2751 cairo_stroke_preserve(
g->cr);
2753 if(
g->area_active_node ==
k)
2764 if(
g->area_cursor_valid)
2766 const float radius =
g->sigma *
g->graph_width / 8.0f / sqrtf(2.0f);
2769 cairo_arc(
g->cr,
g->area_x, y *
g->graph_height, radius, 0, 2. *
M_PI);
2771 cairo_stroke(
g->cr);
2777 float x_pos = (
g->cursor_exposure + 8.0f) / 8.0f *
g->graph_width;
2779 if(x_pos >
g->graph_width || x_pos < 0.0f)
2783 cairo_set_source_rgb(
g->cr, 0.75, 0.50, 0.);
2785 x_pos = (x_pos < 0.0f) ? 0.0f :
g->graph_width;
2793 cairo_move_to(
g->cr, x_pos, 0.0);
2794 cairo_line_to(
g->cr, x_pos,
g->graph_height);
2795 cairo_stroke(
g->cr);
2800 cairo_set_source_surface(cr,
g->cst, 0, 0);
2813 g->area_x = (
event->x -
g->inset);
2814 g->area_y = (
event->y -
g->inset);
2815 g->area_dragging =
FALSE;
2816 g->area_active_node = -1;
2817 g->area_cursor_valid = (
g->area_x > 0.0f &&
g->area_x <
g->graph_width &&
g->area_y > 0.0f &&
g->area_y <
g->graph_height);
2819 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
2833 if(
g->area_dragging)
2840 g->area_x = (
event->x -
g->inset);
2841 g->area_y = (
event->y -
g->inset);
2842 g->area_dragging =
FALSE;
2843 g->area_active_node = -1;
2844 g->area_cursor_valid = (
g->area_x > 0.0f &&
g->area_x <
g->graph_width &&
g->area_y > 0.0f &&
g->area_y <
g->graph_height);
2846 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
2860 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
2866 p->noise =
d->noise;
2867 p->ultra_deep_blacks =
d->ultra_deep_blacks;
2868 p->deep_blacks =
d->deep_blacks;
2869 p->blacks =
d->blacks;
2870 p->shadows =
d->shadows;
2871 p->midtones =
d->midtones;
2872 p->highlights =
d->highlights;
2873 p->whites =
d->whites;
2874 p->speculars =
d->speculars;
2880 gtk_widget_queue_draw(self->
widget);
2884 else if(event->button == 1)
2888 g->area_dragging = 1;
2889 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
2914 if(
g->area_dragging)
2917 const float offset = (-
event->y +
g->area_y) /
g->graph_height * 4.0f;
2918 const float cursor_exposure =
g->area_x /
g->graph_width * 8.0f - 8.0f;
2924 g->area_x = (
event->x -
g->graph_left_space);
2925 g->area_y =
event->y;
2926 g->area_cursor_valid = (
g->area_x > 0.0f &&
g->area_x <
g->graph_width &&
g->area_y > 0.0f &&
g->area_y <
g->graph_height);
2927 g->area_active_node = -1;
2930 if(
g->valid_nodes_x)
2932 const float radius_threshold = fabsf(
g->nodes_x[1] -
g->nodes_x[0]) * 0.45f;
2935 const float delta_x = fabsf(
g->area_x -
g->nodes_x[
i]);
2936 if(delta_x < radius_threshold)
2938 g->area_active_node =
i;
2939 g->area_cursor_valid = 1;
2944 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
2960 if(event->button == 1)
2964 if(
g->area_dragging)
2969 g->area_dragging= 0;
3006 g->mask_display = 0;
3010 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->show_luminance_mask),
g->mask_display);
3029 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
3033 gboolean already_attached =
FALSE;
3035 if(!
IS_NULL_PTR(
g->thumb_preview_entry) &&
g->thumb_preview_hash == preview_hash &&
g->luminance_valid)
3038 already_attached =
TRUE;
3042 if(!already_attached)
3044 void *preview_buf = NULL;
3047 &preview_buf, &preview_entry);
3052 preview_ready =
FALSE;
3057 size_t preview_width = 0;
3058 size_t preview_height = 0;
3062 gboolean keep_new_entry =
FALSE;
3064 if(
g->thumb_preview_entry != preview_entry ||
g->thumb_preview_hash != preview_hash
3065 ||
g->thumb_preview_buf_width != preview_width ||
g->thumb_preview_buf_height != preview_height
3066 || !
g->luminance_valid)
3068 old_entry =
g->thumb_preview_entry;
3069 g->thumb_preview_entry = preview_entry;
3070 g->thumb_preview_hash = preview_hash;
3072 g->thumb_preview_buf_width = preview_width;
3073 g->thumb_preview_buf_height = preview_height;
3074 g->luminance_valid =
TRUE;
3075 g->histogram_valid =
FALSE;
3076 keep_new_entry =
TRUE;
3090 g->pending_preview_hash = preview_hash;
3096 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
3107 const gboolean matched = (
g->pending_preview_hash == hash);
3109 if(!matched)
return;
3111 size_t preview_width = 0;
3112 size_t preview_height = 0;
3114 if(preview_hash != hash)
return;
3116 void *preview_buf = NULL;
3119 &preview_buf, &preview_entry);
3128 gboolean keep_new_entry =
FALSE;
3130 if(
g->thumb_preview_entry != preview_entry ||
g->thumb_preview_hash != preview_hash
3131 ||
g->thumb_preview_buf_width != preview_width ||
g->thumb_preview_buf_height != preview_height
3132 || !
g->luminance_valid)
3134 old_entry =
g->thumb_preview_entry;
3135 g->thumb_preview_entry = preview_entry;
3136 g->thumb_preview_hash = preview_hash;
3137 g->thumb_preview_buf_width = preview_width;
3138 g->thumb_preview_buf_height = preview_height;
3139 g->luminance_valid =
TRUE;
3140 g->histogram_valid =
FALSE;
3141 keep_new_entry =
TRUE;
3152 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
3175 gtk_widget_queue_draw(self->
widget);
3179 float *
const picked,
float *
const picked_min,
float *
const picked_max)
3187 const size_t box[4] = {
3193 const size_t x0 =
MIN(box[0],
width - 1);
3194 const size_t y0 =
MIN(box[1],
height - 1);
3195 const size_t x1 = CLAMP(
MAX(box[2], x0 + 1), 1,
width);
3196 const size_t y1 = CLAMP(
MAX(box[3], y0 + 1), 1,
height);
3199 float minimum = INFINITY;
3200 float maximum = -INFINITY;
3205 for(
size_t y = y0; y < y1; ++y)
3208 for(
size_t x = x0;
x < x1; ++
x)
3212 minimum = fminf(minimum,
value);
3213 maximum = fmaxf(maximum,
value);
3218 if(count == 0)
return FALSE;
3219 *picked = mean / (float)count;
3220 *picked_min = minimum;
3221 *picked_max = maximum;
3222 return isfinite(*picked) && isfinite(*picked_min) && isfinite(*picked_max);
3225 const size_t x = CLAMP((
size_t)roundf(sample->
point[0] *
width), 0,
width - 1);
3226 const size_t y = CLAMP((
size_t)roundf(sample->
point[1] *
height), 0,
height - 1);
3229 *picked_min =
value;
3230 *picked_max =
value;
3231 return isfinite(
value);
3260 size_t preview_width = 0;
3261 size_t preview_height = 0;
3263 if(
IS_NULL_PTR(
g) || (picker !=
g->exposure_boost && picker !=
g->contrast_boost))
3266 (
void *)picker, (
void *)pipe, piece ? piece->
global_hash : 0);
3271 g->area_active_node = -1;
3276 preview_entry =
g->thumb_preview_entry;
3277 preview_width =
g->thumb_preview_buf_width;
3278 preview_height =
g->thumb_preview_buf_height;
3283 if(
IS_NULL_PTR(preview_entry) || preview_width < 1 || preview_height < 1)
3287 dt_print(
DT_DEBUG_DEV,
"[picker/toneequal] no preview mask picker=%p pipe=%p hash=%" PRIu64
"\n",
3288 (
void *)picker, (
void *)pipe, piece ? piece->
global_hash : 0);
3296 float picked_min = NAN;
3297 float picked_max = NAN;
3299 &picked, &picked_min, &picked_max);
3305 dt_print(
DT_DEBUG_DEV,
"[picker/toneequal] mask sample failed picker=%p pipe=%p hash=%" PRIu64
"\n",
3306 (
void *)picker, (
void *)pipe, piece ? piece->
global_hash : 0);
3311 g->cursor_valid = isfinite(picked) && picked > 0.0f;
3312 g->cursor_exposure =
g->cursor_valid ? log2f(picked) : 0.0f;
3314 if(picker ==
g->exposure_boost)
3316 if(isfinite(picked) && picked > 0.0f)
3325 "[picker/toneequal] exposure picker=%p luminance=%g set=%g pipe=%p hash=%" PRIu64
"\n",
3326 (
void *)picker, picked,
p->exposure_boost, (
void *)pipe, piece ? piece->
global_hash : 0);
3331 "[picker/toneequal] exposure picker=%p invalid luminance=%g pipe=%p hash=%" PRIu64
"\n",
3332 (
void *)picker, picked, (
void *)pipe, piece ? piece->
global_hash : 0);
3337 const float fd_old = fminf(picked_min, picked_max);
3338 const float ld_old = fmaxf(picked_min, picked_max);
3340 if(isfinite(fd_old) && isfinite(ld_old) && fd_old > 0.0f && ld_old > fd_old)
3344 const float mix = fd_old * s2 + ld_old * s1;
3352 const float correction = -0.0276f + 0.01823f *
p->feathering + (0.7566f - 1.0f) * contrast;
3353 if(
p->feathering < 5.0f)
3354 contrast += correction;
3355 else if(
p->feathering < 10.0f)
3356 contrast += correction * (2.0f -
p->feathering / 5.0f);
3360 contrast = 0.0235f + 1.1225f * contrast;
3363 p->contrast_boost = contrast;
3370 "[picker/toneequal] contrast picker=%p min=%g max=%g set=%g pipe=%p hash=%" PRIu64
"\n",
3371 (
void *)picker, fd_old, ld_old,
p->contrast_boost, (
void *)pipe,
3377 "[picker/toneequal] contrast picker=%p invalid min=%g max=%g pipe=%p hash=%" PRIu64
"\n",
3378 (
void *)picker, fd_old, ld_old, (
void *)pipe, piece ? piece->
global_hash : 0);
3383 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
3408 for(
size_t k = 0;
k < num_elem; ++
k)
3411 if(!isfinite(
value) ||
value <= 0.0f)
continue;
3417 if(count == 0)
return;
3419 const float picked = mean / (float)count;
3435 g->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
3436 gtk_widget_set_hexpand(GTK_WIDGET(
g->area),
TRUE);
3437 gtk_box_pack_start(GTK_BOX(self->
widget),
3439 "plugins/darkroom/toneequal/graphheight", 280, 120),
3442 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
3443 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
3444 gtk_widget_set_can_focus(GTK_WIDGET(
g->area),
TRUE);
3445 g_signal_connect(G_OBJECT(
g->area),
"draw", G_CALLBACK(
area_draw), self);
3446 g_signal_connect(G_OBJECT(
g->area),
"button-press-event", G_CALLBACK(
area_button_press), self);
3447 g_signal_connect(G_OBJECT(
g->area),
"button-release-event", G_CALLBACK(
area_button_release), self);
3448 g_signal_connect(G_OBJECT(
g->area),
"leave-notify-event", G_CALLBACK(
area_leave_notify), self);
3449 g_signal_connect(G_OBJECT(
g->area),
"enter-notify-event", G_CALLBACK(
area_enter_notify), self);
3450 g_signal_connect(G_OBJECT(
g->area),
"motion-notify-event", G_CALLBACK(
area_motion_notify), self);
3451 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area), _(
"double-click to reset the curve"));
3456 gtk_widget_set_tooltip_text(
g->smoothing, _(
"positive values will produce more progressive tone transitions\n"
3457 "but the curve might become oscillatory in some settings.\n"
3458 "negative values will avoid oscillations and behave more robustly\n"
3459 "but may produce brutal tone transitions and damage local contrast."));
3461 g_signal_connect(G_OBJECT(
g->smoothing),
"value-changed", G_CALLBACK(
smoothing_callback), self);
3467 gtk_widget_set_tooltip_text(
g->exposure_boost, _(
"use this to slide the mask average exposure along channels\n"
3468 "for a better control of the exposure correction with the available nodes.\n"
3469 "the color picker will map the sampled tone to -4 EV."));
3475 gtk_widget_set_tooltip_text(
g->contrast_boost, _(
"use this to counter the averaging effect of the guided filter\n"
3476 "and dilate the mask contrast around -4EV\n"
3477 "this allows to spread the exposure histogram over more channels\n"
3478 "for a better control of the exposure correction.\n"
3479 "the color picker will fit the sampled spread inside the control range."));
3528 gtk_widget_set_tooltip_text(
g->method, _(
"preview the mask and chose the estimator that gives you the\n"
3529 "higher contrast between areas to dodge and areas to burn"));
3533 gtk_widget_set_tooltip_text(
g->details, _(
"'no' affects global and local contrast (safe if you only add contrast)\n"
3534 "'guided filter' only affects global contrast and tries to preserve local contrast\n"
3535 "'averaged guided filter' is a geometric mean of 'no' and 'guided filter' methods\n"
3536 "'eigf' (exposure-independent guided filter) is a guided filter that is exposure-independent, it smooths shadows and highlights the same way (contrary to guided filter which smooths less the highlights)\n"
3537 "'averaged eigf' is a geometric mean of 'no' and 'exposure-independent guided filter' methods"));
3541 gtk_widget_set_tooltip_text(
g->iterations, _(
"number of passes of guided filter to apply\n"
3542 "helps diffusing the edges of the filter at the expense of speed"));
3547 gtk_widget_set_tooltip_text(
g->blending, _(
"diameter of the blur in percent of the largest image size\n"
3548 "warning: big values of this parameter can make the darkroom\n"
3549 "preview much slower if denoise profiled is used."));
3553 gtk_widget_set_tooltip_text(
g->feathering, _(
"precision of the feathering:\n"
3554 "higher values force the mask to follow edges more closely\n"
3555 "but may void the effect of the smoothing\n"
3556 "lower values give smoother gradients and better smoothing\n"
3557 "but may lead to inaccurate edges taping and halos"));
3561 gtk_widget_set_tooltip_text(
g->quantization, _(
"0 disables the quantization.\n"
3562 "higher values posterize the luminance mask to help the guiding\n"
3563 "produce piece-wise smooth areas when using high feathering values"));
3568 const int active_page =
dt_conf_get_int(
"plugins/darkroom/toneequal/gui_page");
3569 gtk_widget_show(gtk_notebook_get_nth_page(
g->notebook, active_page));
3570 gtk_notebook_set_current_page(
g->notebook, active_page);
3573 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
g->notebook),
FALSE,
FALSE, 0);
3602 dt_conf_set_int(
"plugins/darkroom/toneequal/gui_page", gtk_notebook_get_current_page (
g->notebook));
3611 preview_entry =
g->thumb_preview_entry;
3612 g->thumb_preview_entry = NULL;
3615 g->thumb_preview_buf_width = 0;
3616 g->thumb_preview_buf_height = 0;
3617 g->luminance_valid =
FALSE;
3621 if(
g->desc) pango_font_description_free(
g->desc);
3622 if(
g->layout) g_object_unref(
g->layout);
3623 if(
g->cr) cairo_destroy(
g->cr);
3624 if(
g->cst) cairo_surface_destroy(
g->cst);
void dt_bauhaus_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
float dt_bauhaus_slider_get(GtkWidget *widget)
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
void dt_bauhaus_widget_set_quad_active(GtkWidget *widget, int active)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
void dt_bauhaus_combobox_remove_at(GtkWidget *widget, int pos)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
static void set_color(cairo_t *cr, GdkRGBA color)
@ DEVELOP_BLEND_CS_RGB_SCENE
static int pseudo_solve(float *const restrict A, float *const restrict y, const size_t m, const size_t n, const int checks)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
static const float scaling
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
void dt_collection_hint_message(const dt_collection_t *collection)
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
gboolean dt_iop_color_picker_is_visible(const dt_develop_t *dev)
@ DT_LIB_COLORPICKER_SIZE_BOX
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_control_log(const char *msg,...)
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
void dt_control_hinter_message(const struct dt_control_t *s, const char *message)
void dt_control_queue_cursor_by_name(const char *curs_str)
Queue a GTK named cursor for the next cursor commit.
#define dt_control_set_cursor_visible(visible)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
#define __OMP_SIMD__(...)
#define for_each_channel(_var,...)
static void * dt_check_sse_aligned(void *pointer)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define __OMP_DECLARE_SIMD__(...)
#define dt_pixelpipe_cache_free_align(mem)
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
static const dt_aligned_pixel_simd_t value
#define __OMP_FOR_SIMD__(...)
#define __OMP_PARALLEL_FOR_SIMD__(...)
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_update_history_main(dev)
#define dt_dev_pixelpipe_update_history_preview(dev)
dt_dev_pixelpipe_iop_t * dt_dev_distort_get_iop_pipe(struct dt_dev_pixelpipe_t *pipe, struct dt_iop_module_t *module)
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
void dt_dev_coordinates_image_norm_to_preview_abs(dt_develop_t *dev, float *points, size_t num_points)
gboolean dt_dev_rescale_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Scale the ROI to fit within given width/height, centered.
gboolean dt_dev_pixelpipe_has_preview_output(const dt_develop_t *dev, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi)
void dt_dev_coordinates_widget_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Coordinate conversion helpers between widget, normalized image, and absolute image spaces.
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
@ DT_DEV_PIXELPIPE_DISPLAY_PASSTHRU
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
static void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
static void dt_cairo_perceptual_gradient(cairo_pattern_t *grad, double alpha)
void dtgtk_cairo_paint_gamut_check(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_showmask(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
static __DT_CLONE_TARGETS__ int fast_eigf_surface_blur(float *const restrict image, const size_t width, const size_t height, const float sigma, float feathering, const int iterations, const dt_iop_guided_filter_blending_t filter, const float scale, const float quantization, const float quantize_min, const float quantize_max)
static __DT_CLONE_TARGETS__ int fast_surface_blur(float *const restrict image, const size_t width, const size_t height, const int radius, float feathering, const int iterations, const dt_iop_guided_filter_blending_t filter, const float scale, const float quantization, const float quantize_min, const float quantize_max)
static float fast_clamp(const float value, const float bottom, const float top)
GtkWidget * dt_ui_resizable_drawing_area(GtkWidget *area, char *config_str, int default_height, int min_height)
Make a self-drawing widget (typically a GtkDrawingArea graph or scope) vertically resizable.
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
GtkNotebook * dt_ui_notebook_new()
void dt_gui_set_pango_resolution(PangoLayout *layout)
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
static GtkWidget * dt_ui_label_new(const gchar *str)
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled, const dt_develop_blend_colorspace_t blend_cst)
static __DT_CLONE_TARGETS__ void dt_simd_memcpy(const float *const __restrict__ in, float *const __restrict__ out, const size_t num_elem)
void dt_iop_request_focus(dt_iop_module_t *module)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
@ DT_REQUEST_COLORPICK_OFF
#define dt_omploop_sfence()
static void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module) ACQUIRE(&module -> gui_lock)
@ IOP_FLAGS_INCLUDE_IN_STYLES
@ IOP_FLAGS_SUPPORTS_BLENDING
static void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module) RELEASE(&module -> gui_lock)
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_iop_togglebutton_new(dt_iop_module_t *self, const char *section, const gchar *label, const gchar *ctrl_label, GCallback callback, gboolean local, guint accel_key, GdkModifierType mods, DTGTKCairoPaintIconFunc paint, GtkWidget *box)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
int dt_ioppr_get_iop_order(GList *iop_order_list, const char *op_name, const int multi_priority)
Return the iop_order for a given operation/instance pair.
static float mix(const float a, const float b, const float t)
float *const restrict const size_t const size_t const float exposure_boost
dt_iop_luminance_mask_method_t
float *const restrict luminance
float *const restrict const size_t const size_t const float const float const float contrast_boost
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
static const int max_size
dt_masks_form_t * dt_masks_get_visible_form(const struct dt_develop_t *dev)
float DT_ALIGNED_ARRAY dt_colormatrix_t[4][4]
void * dt_pixel_cache_entry_get_data(dt_pixel_cache_entry_t *entry)
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
int dt_dev_pixelpipe_cache_get(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const size_t size, const char *name, const int id, const gboolean alloc, void **data, dt_pixel_cache_entry_t **entry)
Get a cache line from the cache.
int dt_dev_pixelpipe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const gboolean force, dt_pixel_cache_entry_t *cache_entry)
Arbitrarily remove the cache entry matching hash. Entries having a reference count > 0 (inter-thread ...
gboolean dt_dev_pixelpipe_cache_ref_entry_by_hash(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cache entry by hash.
void dt_dev_pixelpipe_cache_wrlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the write lock on the entry.
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
Pixelpipe cache for storing intermediate results in the pixelpipe.
#define DT_PIXELPIPE_CACHE_HASH_INVALID
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
@ DT_SIGNAL_DEVELOP_HISTORY_CHANGE
This signal is raised when develop history is changed no param, no returned value.
@ DT_SIGNAL_HISTORY_RESYNC
This signal is raised once darkroom history has been resynchronized into all live pipelines....
@ DT_SIGNAL_CACHELINE_READY
This signal is raised when one cacheline write lock is released. 1 : uint64_t cacheline hash no retur...
@ DT_SIGNAL_DEVELOP_UI_PIPE_FINISHED
This signal is raised when pipe is finished and the gui is attached no param, no returned value.
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
unsigned __int64 uint64_t
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
struct dt_gui_gtk_t * gui
struct dt_collection_t * collection
struct dt_control_signal_t * signals
struct dt_bauhaus_t * bauhaus
struct dt_develop_t * develop
struct dt_control_t * control
PangoFontDescription * pango_font_desc
dt_lib_colorpicker_size_t size
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
struct dt_develop_t::@19 color_picker
Authoritative darkroom color-picker state.
struct dt_colorpicker_sample_t * primary_sample
struct dt_dev_pixelpipe_t * preview_pipe
struct dt_masks_form_gui_t * form_gui
struct dt_develop_t::@17 roi
struct dt_dev_pixelpipe_t * pipe
dt_iop_buffer_type_t datatype
GModule *dt_dev_operation_t op
dt_iop_global_data_t * data
dt_dev_request_colorpick_flags_t request_color_pick
GtkDarktableToggleButton * off
dt_iop_params_t * default_params
struct dt_develop_t * dev
dt_iop_gui_data_t * gui_data
Region of interest passed through the pixelpipe.
float factors[8] DT_ALIGNED_ARRAY
dt_iop_toneequalizer_filter_t details
float correction_lut[8 *10000+1] DT_ALIGNED_ARRAY
dt_iop_luminance_mask_method_t method
float gradient_left_limit
int histogram[256] DT_ALIGNED_ARRAY
float histogram_first_decile
dt_pixel_cache_entry_t * thumb_preview_entry
float histogram_last_decile
float interpolation_matrix[9 *8] DT_ALIGNED_ARRAY
GtkWidget * exposure_boost
float factors[8] DT_ALIGNED_ARRAY
size_t thumb_preview_buf_height
float gradient_right_limit
GtkWidget * show_luminance_mask
GtkWidget * contrast_boost
float temp_user_params[9] DT_ALIGNED_ARRAY
float gui_lut[256] DT_ALIGNED_ARRAY
GtkWidget * ultra_deep_blacks
size_t thumb_preview_buf_width
uint64_t thumb_preview_hash
uint64_t pending_preview_hash
PangoFontDescription * desc
GtkStyleContext * context
dt_iop_toneequalizer_filter_t details
dt_iop_luminance_mask_method_t method
typedef double((*spd)(unsigned long int wavelength, double TempK))
static void get_shade_from_luminance(cairo_t *cr, const float luminance, const float alpha)
static void draw_exposure_cursor(cairo_t *cr, const double pointerx, const double pointery, const double radius, const float luminance, const float zoom_scale, const int instances, const float alpha)
static void smoothing_callback(GtkWidget *slider, gpointer user_data)
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static gboolean area_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
static gboolean area_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static int compute_luminance_mask(const float *const restrict in, float *const restrict luminance, const size_t width, const size_t height, const size_t ch, const dt_iop_toneequalizer_data_t *const d)
const char ** description(struct dt_iop_module_t *self)
void cairo_draw_hatches(cairo_t *cr, double center[2], double span[2], int instances, double line_width, double shade)
static gboolean area_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
static float pixel_correction(const float exposure, const float *const restrict factors, const float sigma)
int scrolled(struct dt_iop_module_t *self, double x, double y, int up, uint32_t state)
static __DT_CLONE_TARGETS__ void compute_log_histogram_and_stats(const float *const restrict luminance, int histogram[256], const size_t num_elem, int *max_histogram, float *first_decile, float *last_decile)
static void get_channels_gains(float factors[9], const dt_iop_toneequalizer_params_t *p)
static void _develop_history_resync_callback(gpointer instance, gpointer user_data)
static void match_color_to_background(cairo_t *cr, const float exposure, const float alpha)
static void build_interpolation_matrix(float A[9 *8], const float sigma)
static gboolean in_mask_editing(dt_iop_module_t *self)
void show_guiding_controls(struct dt_iop_module_t *self)
static void init_nodes_y(dt_iop_toneequalizer_gui_data_t *g)
static gboolean update_curve_lut(struct dt_iop_module_t *self)
static void _switch_cursors(struct dt_iop_module_t *self)
void gui_focus(struct dt_iop_module_t *self, gboolean in)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static const float centers_ops[8] DT_ALIGNED_ARRAY
static __DT_CLONE_TARGETS__ void compute_lut_correction(struct dt_iop_toneequalizer_gui_data_t *g, const float offset, const float scaling)
static int set_new_params_interactive(const float control_exposure, const float exposure_offset, const float blending_sigma, dt_iop_toneequalizer_gui_data_t *g, dt_iop_toneequalizer_params_t *p)
void gui_reset(struct dt_iop_module_t *self)
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
static void compress_shadows_highlight_preset_set_exposure_params(dt_iop_toneequalizer_params_t *p, const float step)
void gui_init(struct dt_iop_module_t *self)
static void dilate_shadows_highlight_preset_set_exposure_params(dt_iop_toneequalizer_params_t *p, const float step)
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
static void init_nodes_x(dt_iop_toneequalizer_gui_data_t *g)
static void _develop_cacheline_ready_callback(gpointer instance, const guint64 hash, gpointer user_data)
static int compute_channels_gains(const float in[9], float out[9])
static void compute_correction_lut(float *restrict lut, const float sigma, const float *const restrict factors)
static const dt_colormatrix_t gauss_kernel
void cleanup_global(dt_iop_module_so_t *module)
static void gui_cache_init(struct dt_iop_module_t *self)
static void update_histogram(struct dt_iop_module_t *const self)
static uint64_t _current_preview_luminance_hash(dt_iop_module_t *self, size_t *width, size_t *height)
static void _develop_ui_pipe_started_callback(gpointer instance, gpointer user_data)
static gboolean area_enter_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
void update_exposure_sliders(dt_iop_toneequalizer_gui_data_t *g, dt_iop_toneequalizer_params_t *p)
static gboolean area_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
static gboolean area_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
void gui_cleanup(struct dt_iop_module_t *self)
dt_iop_toneequalizer_filter_t
void init_presets(dt_iop_module_so_t *self)
int mouse_leave(struct dt_iop_module_t *self)
static gboolean notebook_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static gboolean _sample_picker_luminance_mask(const float *const buffer, const size_t width, const size_t height, float *const picked, float *const picked_min, float *const picked_max)
static void get_channels_factors(float factors[9], const dt_iop_toneequalizer_params_t *p)
static void _develop_ui_pipe_finished_callback(gpointer instance, gpointer user_data)
static __DT_CLONE_TARGETS__ void display_luminance_mask(const float *const restrict in, const float *const restrict luminance, float *const restrict out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const dt_dev_pixelpipe_t *pipe, const size_t ch)
static gboolean _init_drawing(dt_iop_module_t *const restrict self, GtkWidget *widget, dt_iop_toneequalizer_gui_data_t *const restrict g)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static float get_luminance_from_buffer(const float *const buffer, const size_t width, const size_t height, const size_t x, const size_t y)
void init_global(dt_iop_module_so_t *module)
void autoset(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *i)
static int commit_channels_gains(const float factors[9], dt_iop_toneequalizer_params_t *p)
int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
static int compute_channels_factors(const float factors[8], float out[9], const float sigma)
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Update tone equalizer sliders from one picker sample.
static void show_luminance_mask_callback(GtkWidget *togglebutton, GdkEventButton *event, dt_iop_module_t *self)
void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const restrict ivoid, void *const restrict ovoid)
static void invalidate_luminance_cache(dt_iop_module_t *const self)
static __DT_CLONE_TARGETS__ void apply_toneequalizer(const float *const restrict in, const float *const restrict luminance, float *const restrict out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const size_t ch, const dt_iop_toneequalizer_data_t *const d)