88#define RETOUCH_NO_FORMS 300
89#define RETOUCH_MAX_SCALES 15
90#define RETOUCH_NO_SCALES (RETOUCH_MAX_SCALES + 2)
92#define RETOUCH_PREVIEW_LVL_MIN -3.0f
93#define RETOUCH_PREVIEW_LVL_MAX 3.0f
240 return _(
"re_touch");
245 return _(
"split-frequency|healing|cloning|stamp");
253 _(
"linear, RGB, scene-referred"),
254 _(
"geometric and frequential, RGB"),
255 _(
"linear, RGB, scene-referred"));
276 const int new_version)
278 if(old_version == 1 && new_version == 3)
280 typedef struct dt_iop_retouch_form_data_v1_t
291 float fill_brightness;
292 } dt_iop_retouch_form_data_v1_t;
293 typedef struct dt_iop_retouch_params_v1_t
301 int merge_from_scale;
303 float preview_levels[3];
313 float fill_brightness;
314 } dt_iop_retouch_params_v1_t;
316 dt_iop_retouch_params_v1_t *o = (dt_iop_retouch_params_v1_t *)old_params;
323 dt_iop_retouch_form_data_v1_t of = o->rt_forms[
i];
324 n->rt_forms[
i].algorithm = of.algorithm;
325 n->rt_forms[
i].blur_radius = of.blur_radius;
326 n->rt_forms[
i].blur_type = of.blur_type;
327 n->rt_forms[
i].distort_mode = 1;
328 n->rt_forms[
i].fill_brightness = of.fill_brightness;
329 n->rt_forms[
i].fill_color[0] = of.fill_color[0];
330 n->rt_forms[
i].fill_color[1] = of.fill_color[1];
331 n->rt_forms[
i].fill_color[2] = of.fill_color[2];
332 n->rt_forms[
i].fill_mode = of.fill_mode;
333 n->rt_forms[
i].formid = of.formid;
334 n->rt_forms[
i].scale = of.scale;
336 n->algorithm = o->algorithm;
337 n->blur_radius = o->blur_radius;
338 n->blur_type = o->blur_type;
339 n->curr_scale = o->curr_scale;
340 n->fill_brightness = o->fill_brightness;
341 n->fill_color[0] = o->fill_color[0];
342 n->fill_color[1] = o->fill_color[1];
343 n->fill_color[2] = o->fill_color[2];
344 n->fill_mode = o->fill_mode;
345 n->merge_from_scale = o->merge_from_scale;
346 n->num_scales = o->num_scales;
347 n->preview_levels[0] = o->preview_levels[0];
348 n->preview_levels[1] = o->preview_levels[1];
349 n->preview_levels[2] = o->preview_levels[2];
351 n->max_heal_iter = 1000;
355 if(old_version == 2 && new_version == 3)
357 typedef struct dt_iop_retouch_params_v2_t
365 int merge_from_scale;
367 float preview_levels[3];
374 float fill_brightness;
375 } dt_iop_retouch_params_v2_t;
377 dt_iop_retouch_params_v2_t *o = (dt_iop_retouch_params_v2_t *)old_params;
383 memcpy(
n, o,
sizeof(dt_iop_retouch_params_v2_t));
385 n->max_heal_iter = 1000;
401 if(
p->rt_forms[
i].formid == formid) index =
i;
418 return selected_group_entry ? selected_group_entry->
formid : 0;
431 for(
const GList *forms = grp->
points; forms; forms = g_list_next(forms))
434 if(grpt->
formid == formid)
436 form_point_group = grpt;
442 return form_point_group;
450 if(grpt) opacity = grpt->
opacity;
458 = (GdkRGBA){.red =
p->fill_color[0], .green =
p->fill_color[1], .blue =
p->fill_color[2], .alpha = 1.0 };
459 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(
g->colorpick), &c);
470 gtk_widget_hide(GTK_WIDGET(
g->vbox_blur));
471 gtk_widget_hide(GTK_WIDGET(
g->vbox_fill));
474 gtk_widget_show(GTK_WIDGET(
g->vbox_blur));
475 gtk_widget_hide(GTK_WIDGET(
g->vbox_fill));
478 gtk_widget_hide(GTK_WIDGET(
g->vbox_blur));
479 gtk_widget_show(GTK_WIDGET(
g->vbox_fill));
481 gtk_widget_show(GTK_WIDGET(
g->hbox_color_pick));
483 gtk_widget_hide(GTK_WIDGET(
g->hbox_color_pick));
487 gtk_widget_hide(GTK_WIDGET(
g->vbox_blur));
488 gtk_widget_hide(GTK_WIDGET(
g->vbox_fill));
492 if(
g->display_wavelet_scale)
493 gtk_widget_show(GTK_WIDGET(
g->vbox_preview_scale));
495 gtk_widget_hide(GTK_WIDGET(
g->vbox_preview_scale));
499 if(selected_formid > 0)
502 gtk_widget_show(GTK_WIDGET(
g->sl_mask_opacity));
504 gtk_widget_hide(GTK_WIDGET(
g->sl_mask_opacity));
514 gtk_label_set_text(
g->label_form_selected, form->
name);
516 gtk_label_set_text(
g->label_form_selected, _(
"none"));
532 gboolean selection_changed =
FALSE;
548 selection_changed =
TRUE;
562 selection_changed =
TRUE;
574 selection_changed =
TRUE;
583 gtk_widget_show(GTK_WIDGET(
g->sl_mask_opacity));
585 gtk_widget_hide(GTK_WIDGET(
g->sl_mask_opacity));
604 CLAMP(opacity, 0.05f, 1.0f), &member);
625 if(source_scale != dest_scale && source_scale >= 0 && dest_scale >= 0)
629 if(
p->rt_forms[
i].scale == source_scale)
p->rt_forms[
i].scale = dest_scale;
656 const int scale =
p->curr_scale;
662 if(
p->rt_forms[
i].formid != 0 &&
p->rt_forms[
i].scale == scale) count++;
666 gtk_widget_set_sensitive(
g->bt_copy_scale, count > 0);
674 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
688 if(
p->rt_forms[
i].scale == scale)
690 const int formid =
p->rt_forms[
i].formid;
706 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
727 int new_form_index = 0;
735 const int formid = grpt->
formid;
743 forms_d[new_form_index] =
p->rt_forms[form_index];
751 forms_d[new_form_index].
formid = formid;
752 forms_d[new_form_index].
scale =
p->curr_scale;
753 forms_d[new_form_index].
algorithm =
p->algorithm;
756 switch(forms_d[new_form_index].algorithm)
759 forms_d[new_form_index].
blur_type =
p->blur_type;
763 forms_d[new_form_index].
fill_mode =
p->fill_mode;
764 forms_d[new_form_index].
fill_color[0] =
p->fill_color[0];
765 forms_d[new_form_index].
fill_color[1] =
p->fill_color[1];
766 forms_d[new_form_index].
fill_color[2] =
p->fill_color[2];
779 p->rt_forms[
i] = forms_d[
i];
806 gchar *str = g_strdup_printf(
"%d", nb);
807 gtk_label_set_text(
g->label_form, str);
815 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
820 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
FALSE);
838 if(ft >= roi_out->
y + roi_out->
height || ft + fh <= roi_out->y || fl >= roi_out->
x + roi_out->
width
839 || fl + fw <= roi_out->
x)
847 size_t points_count,
float *
new)
851 for(
size_t i = 0;
i < points_count * 2;
i += 2)
853 new[
i] = points[
i] * scalex;
854 new[
i + 1] = points[
i + 1] * scaley;
860 const float *target,
const float *source,
float *dx,
float *dy,
861 const int distort_mode)
866 if(distort_mode == 1)
873 points[0] = target[0] * pipe->
iwidth;
874 points[1] = target[1] * pipe->
iheight;
875 points[2] = source[0] * pipe->
iwidth;
876 points[3] = source[1] * pipe->
iheight;
883 if(distort_mode == 1)
885 *dx = points[0] - points[2];
886 *dy = points[1] - points[3];
890 *dx = (points[0] - points[2]) * roi->
scale;
891 *dy = (points[1] - points[3]) * roi->
scale;
901 const int distort_mode)
938static inline __attribute__((always_inline))
void rt_clamp_minmax(
float levels_old[3],
float levels_new[3])
941 if((levels_old[0] != levels_new[0] || levels_old[2] != levels_new[2]) && levels_old[1] == levels_new[1])
944 if(levels_old[2] != levels_old[0])
950 const float percentage = (levels_old[1] - levels_old[0]) / (levels_old[2] - levels_old[0]);
951 levels_new[1] = left + (right - left) * percentage;
952 levels_new[0] = left;
953 levels_new[2] = right;
958 if(levels_new[0] == 0.f && levels_new[1] == 0.f && levels_new[2] == 0.f)
960 levels_new[0] = -1.5f;
962 levels_new[2] = 1.5f;
966 if(levels_new[2] < levels_new[0] + 0.05f * 2.f) levels_new[2] = levels_new[0] + 0.05f * 2.f;
967 if(levels_new[1] < levels_new[0] + 0.05f) levels_new[1] = levels_new[0] + 0.05f;
968 if(levels_new[1] > levels_new[2] - 0.05f) levels_new[1] = levels_new[2] - 0.05f;
975 const float percentage = (levels_new[1] - levels_new[0]) / (levels_new[2] - levels_new[0]);
976 levels_new[1] = left + (right - left) * percentage;
977 levels_new[0] = left;
978 levels_new[2] = right;
1012 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
gui->
off),
TRUE);
1026 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
FALSE);
1027 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_showmask),
FALSE);
1028 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_suppress),
FALSE);
1029 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->colorpicker),
FALSE);
1056 = (GdkRGBA){.red =
p->fill_color[0], .green =
p->fill_color[1], .blue =
p->fill_color[2], .alpha = 1.0 };
1057 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &c);
1058 p->fill_color[0] = c.red;
1059 p->fill_color[1] = c.green;
1060 p->fill_color[2] = c.blue;
1067 p->rt_forms[index].fill_color[0] =
p->fill_color[0];
1068 p->rt_forms[index].fill_color[1] =
p->fill_color[1];
1069 p->rt_forms[index].fill_color[2] =
p->fill_color[2];
1077#define RT_WDBAR_INSET 0.2f
1078#define lw DT_PIXEL_APPLY_DPI(1.0f)
1084 snprintf(text,
sizeof(text),
"%i",
p->curr_scale);
1085 gtk_label_set_text(
g->lbl_curr_scale, text);
1087 snprintf(text,
sizeof(text),
"%i",
p->num_scales);
1088 gtk_label_set_text(
g->lbl_num_scales, text);
1090 snprintf(text,
sizeof(text),
"%i",
p->merge_from_scale);
1091 gtk_label_set_text(
g->lbl_merge_from_scale, text);
1102 if(
p->num_scales == num_scales)
return;
1104 p->num_scales = num_scales;
1106 if(
p->num_scales <
p->merge_from_scale)
p->merge_from_scale =
p->num_scales;
1121 if(
p->curr_scale == curr_scale)
return;
1123 p->curr_scale = curr_scale;
1133 &&
g->preview_auto_levels == 0 &&
p->curr_scale > 0 &&
p->curr_scale <=
p->num_scales)
1135 g->preview_auto_levels = 1;
1136 g->displayed_wavelet_scale = 1;
1152 const int merge_from_scale = CLAMP(_merge_from_scale, 0,
p->num_scales);
1153 if(
p->merge_from_scale == merge_from_scale)
return;
1155 p->merge_from_scale = merge_from_scale;
1166 g->wdbar_mouse_x =
g->wdbar_mouse_y = -1;
1168 g->lower_cursor =
g->upper_cursor =
FALSE;
1169 g->lower_margin =
g->upper_margin =
FALSE;
1171 gtk_widget_queue_draw(
g->wd_bar);
1182 GtkAllocation allocation;
1183 gtk_widget_get_allocation(widget, &allocation);
1185 const float box_w = (allocation.width - 2.0f * inset) / (
float)
RETOUCH_NO_SCALES;
1187 if(event->button == 1)
1196 else if(
g->upper_margin)
1203 else if (
g->curr_scale >= 0)
1207 gtk_widget_queue_draw(
g->wd_bar);
1215 if(event->button == 1)
g->is_dragging = 0;
1217 gtk_widget_queue_draw(
g->wd_bar);
1235 else if(
g->upper_margin)
1237 else if (
g->curr_scale >= 0)
1241 gtk_widget_queue_draw(
g->wd_bar);
1250 GtkAllocation allocation;
1251 gtk_widget_get_allocation(widget, &allocation);
1253 const float box_w = (allocation.width - 2.0f * inset) / (
float)
RETOUCH_NO_SCALES;
1254 const float sh = 3.0f *
lw + inset;
1258 g->wdbar_mouse_x = CLAMP(event->x - inset, 0, allocation.width - 2.0f * inset - 1.0f);
1259 g->wdbar_mouse_y =
event->y;
1261 g->curr_scale =
g->wdbar_mouse_x / box_w;
1262 g->lower_cursor =
g->upper_cursor =
FALSE;
1263 g->lower_margin =
g->upper_margin =
FALSE;
1264 if(
g->wdbar_mouse_y <= sh)
1266 g->upper_margin =
TRUE;
1267 float middle = box_w * (0.5f + (float)
p->merge_from_scale);
1268 g->upper_cursor = (
g->wdbar_mouse_x >= (middle - inset)) && (
g->wdbar_mouse_x <= (middle + inset));
1269 if (!(
g->is_dragging))
g->curr_scale = -1;
1271 else if (
g->wdbar_mouse_y >= allocation.height - sh)
1273 g->lower_margin =
TRUE;
1274 float middle = box_w * (0.5f + (float)
p->num_scales);
1275 g->lower_cursor = (
g->wdbar_mouse_x >= (middle - inset)) && (
g->wdbar_mouse_x <= (middle + inset));
1276 if (!(
g->is_dragging))
g->curr_scale = -1;
1285 gtk_widget_queue_draw(
g->wd_bar);
1294 has_shapes = (
p->rt_forms[
i].formid != 0 &&
p->rt_forms[
i].scale == scale);
1305 GdkRGBA border = {0.066, 0.066, 0.066, 1};
1306 GdkRGBA original = {.1, .1, .1, 1};
1307 GdkRGBA inactive = {.15, .15, .15, 1};
1308 GdkRGBA active = {.35, .35, .35, 1};
1309 GdkRGBA merge_from = {.5, .5, .5, 1};
1310 GdkRGBA residual = {.8, .8, .8, 1};
1311 GdkRGBA shapes = {.75, .5, .0, 1};
1315 const int first_scale_visible = (
g->first_scale_visible > 0) ?
g->first_scale_visible :
RETOUCH_MAX_SCALES;
1317 GtkAllocation allocation;
1318 gtk_widget_get_allocation(widget, &allocation);
1321 cairo_t *cr = cairo_create(cst);
1324 gdk_cairo_set_source_rgba(cr, &inactive);
1330 const int mk = 2 * inset;
1331 const float sh = 3.0f *
lw + inset;
1332 const float box_w = (allocation.width - 2.0f * inset) / (
float)
RETOUCH_NO_SCALES;
1333 const float box_h = allocation.height - 2.0f * sh;
1336 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
1342 else if(
i ==
p->num_scales + 1)
1344 else if(
i >=
p->merge_from_scale && i <= p->num_scales &&
p->merge_from_scale > 0)
1346 else if(i <= p->num_scales)
1351 gdk_cairo_set_source_rgba(cr, &
color);
1352 cairo_rectangle(cr, box_w *
i + inset, sh, box_w, box_h);
1356 if(
i >= first_scale_visible && i <= p->num_scales)
1358 gdk_cairo_set_source_rgba(cr, &merge_from);
1359 cairo_rectangle(cr, box_w *
i + inset,
lw, box_w, 2.0f *
lw);
1366 cairo_set_line_width(cr,
lw);
1367 gdk_cairo_set_source_rgba(cr, &shapes);
1368 cairo_rectangle(cr, box_w *
i + inset +
lw / 2.0f, allocation.height - sh, box_w -
lw, 2.0f *
lw);
1373 cairo_set_line_width(cr,
lw);
1374 gdk_cairo_set_source_rgba(cr, &border);
1375 cairo_rectangle(cr, box_w *
i + inset, sh, box_w, box_h);
1379 cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
1383 if(
p->curr_scale >=
p->merge_from_scale &&
p->curr_scale <=
p->num_scales &&
p->merge_from_scale > 0)
1390 cairo_set_line_width(cr,
lw);
1391 gdk_cairo_set_source_rgba(cr, &
color);
1392 middle = box_w * (0.5f + (float)
p->curr_scale);
1393 cairo_arc(cr, middle + inset, 0.5f * box_h + sh, 0.5f * inset, 0, 2.0f *
M_PI);
1399 if(
g->curr_scale >= 0)
1401 cairo_set_line_width(cr,
lw);
1402 if(
g->curr_scale ==
p->num_scales + 1)
color = inactive;
1403 else color = residual;
1404 gdk_cairo_set_source_rgba(cr, &
color);
1405 cairo_rectangle(cr, box_w *
g->curr_scale + inset +
lw, sh +
lw, box_w - 2.0f *
lw, box_h - 2.0f *
lw);
1412 middle = box_w * (0.5f + (float)
p->num_scales);
1415 cairo_set_source_rgb(cr, 0.67, 0.67, 0.67);
1420 cairo_set_source_rgb(cr, 0.54, 0.54, 0.54);
1425 middle = box_w * (0.5f + (float)
p->merge_from_scale);
1428 cairo_set_source_rgb(cr, 0.67, 0.67, 0.67);
1433 cairo_set_source_rgb(cr, 0.54, 0.54, 0.54);
1439 cairo_set_source_surface(crf, cst, 0, 0);
1441 cairo_surface_destroy(cst);
1474 for (
int i = 0;
i < 3;
i++)
p->preview_levels[
i] = dlevels[
i];
1503 p->rt_forms[index].fill_color[0] =
p->fill_color[0];
1504 p->rt_forms[index].fill_color[1] =
p->fill_color[1];
1505 p->rt_forms[index].fill_color[2] =
p->fill_color[2];
1520 int scale_copied = 0;
1521 const int active = !gtk_toggle_button_get_active(togglebutton);
1525 if(togglebutton == (GtkToggleButton *)
g->bt_copy_scale)
1527 g->copied_scale = (active) ?
p->curr_scale : -1;
1529 else if(togglebutton == (GtkToggleButton *)
g->bt_paste_scale)
1535 g->copied_scale = -1;
1538 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_copy_scale),
g->copied_scale >= 0);
1539 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_paste_scale),
g->copied_scale >= 0);
1540 gtk_widget_set_sensitive(
g->bt_paste_scale,
g->copied_scale >= 0);
1553 return module->request_mask_display && !g->mask_display && !g->display_wavelet_scale;
1562 return g->mask_display ||
g->display_wavelet_scale ||
g->suppress_mask;
1574 const int variant = (
g->mask_display ? 1 : 0) | (
g->display_wavelet_scale ? 2 : 0) | (
g->suppress_mask ? 4 : 0);
1596 module->request_mask_display = display_request;
1609 dt_control_log(_(
"cannot display scales when the blending mask is displayed"));
1612 gtk_toggle_button_set_active(togglebutton,
FALSE);
1617 if(self->
gui->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
gui->
off), 1);
1620 g->display_wavelet_scale = !gtk_toggle_button_get_active(togglebutton);
1632 &&
g->preview_auto_levels == 0 &&
p->curr_scale > 0 &&
p->curr_scale <=
p->num_scales)
1634 g->preview_auto_levels = 1;
1635 g->displayed_wavelet_scale = 1;
1641 gtk_toggle_button_set_active(togglebutton,
g->display_wavelet_scale);
1654 if(
g->preview_auto_levels == 2)
1656 g->preview_auto_levels = -1;
1660 for(
int i = 0;
i < 3;
i++)
p->preview_levels[
i] =
g->preview_levels[
i];
1668 for(
int i = 0;
i < 3;
i++) dlevels[
i] =
p->preview_levels[
i];
1674 g->preview_auto_levels = 0;
1679 gtk_widget_queue_draw(GTK_WIDGET(
g->wd_bar));
1688 if(self->
gui->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
gui->
off), 1);
1692 if(
g->preview_auto_levels == 0)
1694 g->preview_auto_levels = 1;
1758 if(event->button == 1)
1790 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
1822 if(togglebutton == (GtkToggleButton *)
g->bt_blur)
1824 else if(togglebutton == (GtkToggleButton *)
g->bt_clone)
1826 else if(togglebutton == (GtkToggleButton *)
g->bt_heal)
1828 else if(togglebutton == (GtkToggleButton *)
g->bt_fill)
1832 gboolean accept =
TRUE;
1841 if(accept)
p->algorithm = new_algo;
1858 if(
p->algorithm !=
p->rt_forms[index].algorithm)
1860 p->rt_forms[index].algorithm =
p->algorithm;
1869 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
g->bt_polygon)))
1871 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
g->bt_circle)))
1873 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
g->bt_ellipse)))
1875 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
g->bt_brush)))
1920 dt_control_log(_(
"cannot display masks when the blending mask is displayed"));
1922 gtk_toggle_button_set_active(togglebutton,
FALSE);
1926 g->mask_display = !gtk_toggle_button_get_active(togglebutton);
1930 if(module->
gui->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->
gui->
off), 1);
1935 gtk_toggle_button_set_active(togglebutton,
g->mask_display);
1944 g->suppress_mask = !gtk_toggle_button_get_active(togglebutton);
1950 if(module->
gui->
off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->
gui->
off), 1);
1955 gtk_toggle_button_set_active(togglebutton,
g->suppress_mask);
1964 if(w ==
g->cmb_fill_mode)
1977 p->rt_forms[index].blur_type =
p->blur_type;
1978 p->rt_forms[index].blur_radius =
p->blur_radius;
1982 p->rt_forms[index].fill_mode =
p->fill_mode;
1983 p->rt_forms[index].fill_brightness =
p->fill_brightness;
2010 d->preview_levels[1] = 0.f;
2017 const int program = 21;
2071 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
2083 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
FALSE);
2089 if(
g->display_wavelet_scale ||
g->mask_display ||
g->suppress_mask)
2116 const float require = 2.0f;
2117 const float require_cl = 1.0f
2118 + ((
p->num_scales > 0) ? 4.0f : 2.0f);
2122 tiling->factor = 2.0f + require;
2123 tiling->factor_cl = 2.0f + require_cl;
2125 tiling->maxbuf_cl = 1.0f;
2158 gchar *str = g_strdup_printf(
"%d", nb);
2159 gtk_label_set_text(
g->label_form, str);
2184 gtk_widget_queue_draw(GTK_WIDGET(
g->wd_bar));
2193 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_display_wavelet_scale),
g->display_wavelet_scale);
2194 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_copy_scale),
g->copied_scale >= 0);
2195 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_paste_scale),
g->copied_scale >= 0);
2196 gtk_widget_set_sensitive(
g->bt_paste_scale,
g->copied_scale >= 0);
2207 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
2212 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
FALSE);
2217 for(
int i = 0;
i < 3;
i++) dlevels[
i] =
p->preview_levels[
i];
2226 g->copied_scale = -1;
2227 g->mask_display = 0;
2228 g->suppress_mask = 0;
2229 g->display_wavelet_scale = 0;
2230 g->displayed_wavelet_scale = 0;
2233 g->preview_auto_levels = 0;
2235 g->preview_levels[1] = 0.f;
2239 g->wdbar_mouse_x =
g->wdbar_mouse_y = -1;
2241 g->lower_cursor =
g->upper_cursor =
FALSE;
2242 g->lower_margin =
g->upper_margin =
FALSE;
2257 g->label_form = GTK_LABEL(gtk_label_new(
"-1"));
2259 gtk_widget_set_tooltip_text(hbox_shapes,
2260 _(
"to add a shape select an algorithm and a shape type and click on the image.\n"
2261 "shapes are added to the current scale"));
2264 N_(
"show and edit shapes in restricted mode"),
2271 .owner_module = self,
2272 .creation_module = self,
2273 .buttons = shape_buttons,
2275 .action_section = N_(
"shapes"),
2286 gtk_box_pack_start(GTK_BOX(hbox_shapes), shape_buttons_box,
FALSE,
FALSE, 0);
2298 self, N_(
"tools"), N_(
"activate blur tool"), N_(
"change algorithm for current form"),
2302 self, N_(
"tools"), N_(
"activate fill tool"), N_(
"change algorithm for current form"),
2306 self, N_(
"tools"), N_(
"activate cloning tool"), N_(
"change algorithm for current form"),
2310 self, N_(
"tools"), N_(
"activate healing tool"), N_(
"change algorithm for current form"),
2314 gchar *tt2 = g_strdup_printf(
"%s\n%s", _(
"ctrl+click to change tool for current form"),
2315 _(
"shift+click to set the tool as default"));
2316 gchar *tt = g_strdup_printf(
"%s\n%s", _(
"activate blur tool"), tt2);
2317 gtk_widget_set_tooltip_text(
g->bt_blur, tt);
2319 tt = g_strdup_printf(
"%s\n%s", _(
"activate fill tool"), tt2);
2320 gtk_widget_set_tooltip_text(
g->bt_fill, tt);
2322 tt = g_strdup_printf(
"%s\n%s", _(
"activate cloning tool"), tt2);
2323 gtk_widget_set_tooltip_text(
g->bt_clone, tt);
2325 tt = g_strdup_printf(
"%s\n%s", _(
"activate healing tool"), tt2);
2326 gtk_widget_set_tooltip_text(
g->bt_heal, tt);
2331 GtkWidget *grid_wd_labels = gtk_grid_new();
2332 gtk_grid_set_column_homogeneous(GTK_GRID(grid_wd_labels),
FALSE);
2334 gtk_grid_attach(GTK_GRID(grid_wd_labels),
dt_ui_label_new(_(
"scales:")), 0, 0, 1, 1);
2336 gtk_label_set_width_chars(
g->lbl_num_scales, 2);
2337 gtk_grid_attach(GTK_GRID(grid_wd_labels), GTK_WIDGET(
g->lbl_num_scales), 1, 0, 1, 1);
2339 gtk_grid_attach(GTK_GRID(grid_wd_labels),
dt_ui_label_new(_(
"current:")), 0, 1, 1, 1);
2341 gtk_label_set_width_chars(
g->lbl_curr_scale, 2);
2342 gtk_grid_attach(GTK_GRID(grid_wd_labels), GTK_WIDGET(
g->lbl_curr_scale), 1, 1, 1, 1);
2344 gtk_grid_attach(GTK_GRID(grid_wd_labels),
dt_ui_label_new(_(
"merge from:")), 0, 2, 1, 1);
2346 gtk_label_set_width_chars(
g->lbl_merge_from_scale, 2);
2347 gtk_grid_attach(GTK_GRID(grid_wd_labels), GTK_WIDGET(
g->lbl_merge_from_scale), 1, 2, 1, 1);
2350 g->wd_bar = gtk_drawing_area_new();
2352 gtk_widget_set_tooltip_text(
g->wd_bar, _(
"top slider adjusts where the merge scales start\n"
2353 "bottom slider adjusts the number of scales\n"
2354 "dot indicates the current scale\n"
2355 "top line indicates that the scale is visible at current zoom level\n"
2356 "bottom line indicates that the scale has shapes on it"));
2357 g_signal_connect(G_OBJECT(
g->wd_bar),
"draw", G_CALLBACK(
rt_wdbar_draw), self);
2362 g_signal_connect(G_OBJECT(
g->wd_bar),
"scroll-event", G_CALLBACK(
rt_wdbar_scrolled), self);
2363 gtk_widget_add_events(GTK_WIDGET(
g->wd_bar), GDK_POINTER_MOTION_MASK
2364 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
2382 gtk_box_pack_end(GTK_BOX(hbox_scale), gtk_grid_new(),
TRUE,
TRUE, 0);
2393 gtk_box_pack_end(GTK_BOX(hbox_scale), gtk_grid_new(),
TRUE,
TRUE, 0);
2405 gtk_box_pack_start(GTK_BOX(
g->vbox_preview_scale), lbl_psc,
FALSE,
TRUE, 0);
2410 #define NEUTRAL_GRAY 0.5
2415 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->preview_levels_gslider), _(
"adjust preview levels"));
2424 (
g->preview_levels_gslider)->min_spacing = 0.05;
2425 g_signal_connect(G_OBJECT(
g->preview_levels_gslider),
"value-changed", G_CALLBACK(
rt_gslider_changed), self);
2427 gtk_box_pack_start(GTK_BOX(prev_lvl), GTK_WIDGET(
g->preview_levels_gslider),
TRUE,
TRUE, 0);
2434 gtk_box_pack_start(GTK_BOX(
g->vbox_preview_scale), prev_lvl,
TRUE,
TRUE, 0);
2438 GtkWidget *label1 = gtk_label_new(_(
"shape selected:"));
2439 gtk_label_set_ellipsize(GTK_LABEL(label1), PANGO_ELLIPSIZE_START);
2440 gtk_box_pack_start(GTK_BOX(hbox_shape_sel), label1,
FALSE,
TRUE, 0);
2441 g->label_form_selected = GTK_LABEL(gtk_label_new(
"-1"));
2442 gtk_widget_set_tooltip_text(hbox_shape_sel,
2443 _(
"click on a shape to select it,\nto unselect click on an empty space"));
2444 gtk_box_pack_start(GTK_BOX(hbox_shape_sel), GTK_WIDGET(
g->label_form_selected),
FALSE,
TRUE, 0);
2450 gtk_widget_set_tooltip_text(
g->cmb_fill_mode, _(
"erase the detail or fills with chosen color"));
2454 = (GdkRGBA){.red =
p->fill_color[0], .green =
p->fill_color[1], .blue =
p->fill_color[2], .alpha = 1.0 };
2458 gtk_box_pack_start(GTK_BOX(
g->hbox_color_pick), lbl_fill_color,
FALSE,
TRUE, 0);
2460 g->colorpick = gtk_color_button_new_with_rgba(&
color);
2461 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(
g->colorpick),
FALSE);
2462 gtk_color_button_set_title(GTK_COLOR_BUTTON(
g->colorpick), _(
"select fill color"));
2463 gtk_widget_set_tooltip_text(
g->colorpick, _(
"select fill color"));
2465 gtk_box_pack_start(GTK_BOX(
g->hbox_color_pick), GTK_WIDGET(
g->colorpick),
TRUE,
TRUE, 0);
2468 gtk_widget_set_tooltip_text(
g->colorpicker, _(
"pick fill color from image"));
2470 gtk_box_pack_start(GTK_BOX(
g->vbox_fill),
g->hbox_color_pick,
TRUE,
TRUE, 0);
2475 gtk_widget_set_tooltip_text(
g->sl_fill_brightness,
2476 _(
"adjusts color brightness to fine-tune it. works with erase as well"));
2482 gtk_widget_set_tooltip_text(
g->cmb_blur_type, _(
"type for the blur algorithm"));
2486 gtk_widget_set_tooltip_text(
g->sl_blur_radius, _(
"radius of the selected blur type"));
2492 gtk_widget_set_tooltip_text(
g->sl_mask_opacity, _(
"set the opacity on the selected shape"));
2518 gtk_box_pack_start(GTK_BOX(self->
gui->
widget),
g->vbox_preview_scale,
TRUE,
TRUE, 0);
2570 dt_iop_roi_t *roi_in,
int *_roir,
int *_roib,
int *_roix,
int *_roiy)
2584 for(
const GList *forms = grp->
points; forms; forms = g_list_next(forms))
2589 const int formid = grpt->
formid;
2610 if(ft >= roi_in->
y + roi_in->
height || ft + fh <= roi_in->y || fl >= roi_in->
x + roi_in->
width
2611 || fl + fw <= roi_in->
x)
2620 roiy = fminf(ft, roiy);
2621 roix = fminf(fl, roix);
2622 roir = fmaxf(fl + fw, roir);
2623 roib = fmaxf(ft + fh, roib);
2628 const int overlap = ceilf(4 * (
p->rt_forms[index].blur_radius * roi_in->
scale));
2629 if(roiy > ft) roiy =
MAX(roiy - overlap, ft);
2630 if(roix > fl) roix =
MAX(roix - overlap, fl);
2631 if(roir < fl + fw) roir =
MAX(roir + overlap, fl + fw);
2632 if(roib < ft + fh) roib =
MAX(roib + overlap, ft + fh);
2638 float dx = 0.f, dy = 0.f;
2640 p->rt_forms[index].distort_mode))
2642 roiy = fminf(ft - dy, roiy);
2643 roix = fminf(fl - dx, roix);
2644 roir = fmaxf(fl + fw - dx, roir);
2645 roib = fmaxf(ft + fh - dy, roib);
2661 dt_iop_roi_t *roi_in,
const int formid_src,
const int fl_src,
2662 const int ft_src,
const int fw_src,
const int fh_src,
int *_roir,
2663 int *_roib,
int *_roix,
int *_roiy)
2677 for(
const GList *forms = grp->
points; forms; forms = g_list_next(forms))
2682 const int formid = grpt->
formid;
2685 if(formid == formid_src)
break;
2709 int fl_dest, ft_dest;
2710 float dx = 0.f, dy = 0.f;
2712 p->rt_forms[index].distort_mode))
2721 const int intersects = !(ft_dest + fh < ft_src || ft_src + fh_src < ft_dest || fl_dest + fw < fl_src
2722 || fl_src + fw_src < fl_dest);
2726 roiy = fminf(ft, roiy);
2727 roix = fminf(fl, roix);
2728 roir = fmaxf(fl + fw, roir);
2729 roib = fmaxf(ft + fh, roib);
2732 roiy = fminf(ft + dy, roiy);
2733 roix = fminf(fl + dx, roix);
2734 roir = fmaxf(fl + fw + dx, roir);
2735 roib = fmaxf(ft + fh + dy, roib);
2750 dt_iop_roi_t *roi_in,
int *_roir,
int *_roib,
int *_roix,
int *_roiy)
2764 for(
const GList *forms = grp->
points; forms; forms = g_list_next(forms))
2769 const int formid = grpt->
formid;
2786 int fl_src, ft_src, fw_src, fh_src;
2793 fw_src *= roi_in->
scale, fh_src *= roi_in->
scale, fl_src *= roi_in->
scale, ft_src *= roi_in->
scale;
2796 const int intersects
2797 = !(roib < ft_src || ft_src + fh_src < roiy || roir < fl_src || fl_src + fw_src < roix);
2800 &roir, &roib, &roix, &roiy);
2818 int roir = roi_in->
width + roi_in->
x;
2819 int roib = roi_in->
height + roi_in->
y;
2820 int roix = roi_in->
x;
2821 int roiy = roi_in->
y;
2823 rt_compute_roi_in(self, processing_pipe, piece, roi_in, &roir, &roib, &roix, &roiy);
2825 int roir_prev = -1, roib_prev = -1, roix_prev = -1, roiy_prev = -1;
2827 while(roir != roir_prev || roib != roib_prev || roix != roix_prev || roiy != roiy_prev)
2839 roi_in->
x = CLAMP(roix, 0, scwidth - 1);
2840 roi_in->
y = CLAMP(roiy, 0, scheight - 1);
2841 roi_in->
width = CLAMP(roir - roi_in->
x, 1, scwidth + .5f - roi_in->
x);
2842 roi_in->
height = CLAMP(roib - roi_in->
y, 1, scheight + .5f - roi_in->
y);
2853 for(
int i = 0;
i < stride;
i +=
ch)
2857 dt_linearRGB_to_XYZ(img_src +
i,
XYZ);
2866 for(
int i = 0;
i < stride;
i +=
ch)
2871 dt_XYZ_to_linearRGB(
XYZ, img_src +
i);
2880 float l_max = -INFINITY;
2881 float l_min = INFINITY;
2893 work_profile->
lut_in, work_profile->unbounded_coeffs_in,
2899 dt_linearRGB_to_XYZ(img_src +
i,
XYZ);
2903 l_max =
MAX(l_max,
Lab[0]);
2904 l_min =
MIN(l_min,
Lab[0]);
2909 levels[0] = l_min / 100.f;
2910 levels[2] = l_max / 100.f;
2911 levels[1] = (l_sum / (float)count) / 100.f;
2916 float *img_src,
const int width,
const int height,
const int ch,
2922 const float left =
levels[0];
2923 const float middle =
levels[1];
2924 const float right =
levels[2];
2928 const float delta = (right - left) / 2.0f;
2929 const float mid = left +
delta;
2930 const float tmp = (middle - mid) /
delta;
2931 const float in_inv_gamma = powf(10, tmp);
2943 const float preserved_alpha = img_src[
i + 3];
2948 work_profile->
lut_in, work_profile->unbounded_coeffs_in,
2955 dt_linearRGB_to_XYZ(img_src +
i,
XYZ);
2959 for(
int c = 0; c < 1; c++)
2961 const float L_in = img_src[
i + c] / 100.0f;
2965 img_src[
i + c] = 0.f;
2969 const float percentage = (L_in - left) / (right - left);
2970 img_src[
i + c] = 100.0f * powf(percentage, in_inv_gamma);
2977 work_profile->
lut_out, work_profile->unbounded_coeffs_out,
2985 dt_XYZ_to_linearRGB(
XYZ, img_src +
i);
2988 img_src[
i + 3] = preserved_alpha;
2992#undef RT_WDBAR_INSET
2994#undef RETOUCH_NO_FORMS
2995#undef RETOUCH_MAX_SCALES
2996#undef RETOUCH_NO_SCALES
2998#undef RETOUCH_PREVIEW_LVL_MIN
2999#undef RETOUCH_PREVIEW_LVL_MAX
3004 const int x_from =
MAX(
MAX((roi_1->
x + 1 - padding), roi_2->
x), (roi_2->
x + dx));
3008 const int y_from =
MAX(
MAX((roi_1->
y + 1 - padding), roi_2->
y), (roi_2->
y + dy));
3009 const int y_to =
MIN(
MIN((roi_1->
y + roi_1->
height + 1 + padding), (roi_2->
y + roi_2->
height)),
3010 (roi_2->
y + roi_2->
height + dy));
3012 roi_dest->
x = x_from;
3013 roi_dest->
y = y_from;
3014 roi_dest->
width = x_to - x_from;
3015 roi_dest->
height = y_to - y_from;
3020 const struct dt_iop_roi_t *
const roi_out,
const int ch,
const int dx,
const int dy)
3022 const size_t rowsize =
sizeof(float) *
ch *
MIN(roi_out->
width, roi_in->
width);
3023 const int xoffs = roi_out->
x - roi_in->
x - dx;
3024 const int yoffs = roi_out->
y - roi_in->
y - dy;
3027 for(
int y = 0; y < y_to; y++)
3029 const size_t iindex = ((size_t)(y + yoffs) * roi_in->
width + xoffs) *
ch;
3030 const size_t oindex = (size_t)y * roi_out->
width *
ch;
3031 float *in1 = (
float *)in + iindex;
3032 float *out1 = (
float *)
out + oindex;
3034 memcpy(out1, in1, rowsize);
3040 const int dy,
const int algo)
3042 float *mask_tmp = NULL;
3044 *mask_scaled = NULL;
3048 *roi_mask_scaled = *roi_mask;
3050 roi_mask_scaled->
x = roi_mask->
x * roi_in->
scale;
3051 roi_mask_scaled->
y = roi_mask->
y * roi_in->
scale;
3059 const int x_to = roi_mask_scaled->
width + roi_mask_scaled->
x;
3060 const int y_to = roi_mask_scaled->
height + roi_mask_scaled->
y;
3065 fprintf(stderr,
"rt_build_scaled_mask: error allocating memory\n");
3071 for(
int yy = roi_mask_scaled->
y; yy < y_to; yy++)
3073 const int mask_index = ((int)(yy / roi_in->
scale)) - roi_mask->
y;
3074 if(mask_index < 0 || mask_index >= roi_mask->
height)
continue;
3076 const int mask_scaled_index = (yy - roi_mask_scaled->
y) * roi_mask_scaled->
width;
3078 const float *
m = mask + mask_index * roi_mask->
width;
3079 float *ms = mask_tmp + mask_scaled_index;
3081 for(
int xx = roi_mask_scaled->
x; xx < x_to; xx++, ms++)
3083 const int mx = ((int)(xx / roi_in->
scale)) - roi_mask->
x;
3084 if(mx < 0 || mx >= roi_mask->
width)
continue;
3091 *mask_scaled = mask_tmp;
3097 float *
const mask_scaled,
dt_iop_roi_t *
const roi_mask_scaled,
3098 const float opacity)
3101 for(
int yy = 0; yy < roi_mask_scaled->
height; yy++)
3103 const int mask_index = yy * roi_mask_scaled->
width;
3104 const int src_index = 4 * mask_index;
3105 const int dest_index
3106 = 4 * (((yy + roi_mask_scaled->
y - roi_dest->
y) * roi_dest->
width) + (roi_mask_scaled->
x - roi_dest->
x));
3108 const float *s = img_src + src_index;
3109 const float *
m = mask_scaled + mask_index;
3110 float *
d = img_dest + dest_index;
3112 for(
int xx = 0; xx < roi_mask_scaled->
width; xx++)
3114 const float f =
m[xx] * opacity;
3115 const float f1 = (1.0f -
f);
3119 d[4*xx + c] =
d[4*xx + c] * f1 + s[4*xx + c] *
f;
3126 float *
const mask_scaled,
dt_iop_roi_t *
const roi_mask_scaled,
3127 const float opacity)
3130 for(
int yy = 0; yy < roi_mask_scaled->
height; yy++)
3132 const int mask_index = yy * roi_mask_scaled->
width;
3133 const int dest_index
3134 = (((yy + roi_mask_scaled->
y - roi_img->
y) * roi_img->
width) + (roi_mask_scaled->
x - roi_img->
x)) *
ch;
3136 float *
d = img + dest_index;
3137 const float *
m = mask_scaled + mask_index;
3139 for(
int xx = 0; xx < roi_mask_scaled->
width; xx++,
d +=
ch,
m++)
3141 const float f = (*m) * opacity;
3142 if(
f >
d[3])
d[3] =
f;
3148 dt_iop_roi_t *
const roi_mask_scaled,
const float opacity,
const float *
const fill_color)
3151 for(
int yy = 0; yy < roi_mask_scaled->
height; yy++)
3153 const int mask_index = yy * roi_mask_scaled->
width;
3154 const int dest_index
3155 = (((yy + roi_mask_scaled->
y - roi_in->
y) * roi_in->
width) + (roi_mask_scaled->
x - roi_in->
x)) * 4;
3157 float *
d = in + dest_index;
3158 const float *
m = mask_scaled + mask_index;
3160 for(
int xx = 0; xx < roi_mask_scaled->
width; xx++)
3162 const float f =
m[xx] * opacity;
3165 d[4*xx + c] =
d[4*xx + c] * (1.0f -
f) + fill_color[c] *
f;
3171 dt_iop_roi_t *
const roi_mask_scaled,
const int dx,
const int dy,
const float opacity)
3177 fprintf(stderr,
"retouch_clone: error allocating memory for cloning\n");
3193 dt_iop_roi_t *
const roi_mask_scaled,
const float opacity,
const int blur_type,
3194 const float blur_radius,
const int use_sse)
3196 if(fabsf(blur_radius) <= 0.1f)
return 0;
3198 const float sigma = blur_radius * roi_in->
scale;
3200 float *img_dest = NULL;
3206 fprintf(stderr,
"retouch_blur: error allocating memory for blurring\n");
3215 float Labmax[] = { INFINITY, INFINITY, INFINITY, INFINITY };
3216 float Labmin[] = { -INFINITY, -INFINITY, -INFINITY, -INFINITY };
3230 const float detail = -1.0f;
3267 dt_iop_roi_t *
const roi_mask_scaled,
const int dx,
const int dy,
const float opacity,
const int max_iter)
3269 float *img_src = NULL;
3270 float *img_dest = NULL;
3278 fprintf(stderr,
"retouch_heal: error allocating memory for healing\n");
3288 dt_heal(img_src, img_dest, mask_scaled, roi_mask_scaled->
width, roi_mask_scaled->
height, 4, max_iter);
3311 if(scale > wt_p->
scales + 1)
return 0;
3323 const int mask_display
3331 scale =
p->num_scales + 1;
3344 for(
const GList *forms = grp->
points; forms; forms = g_list_next(forms))
3349 fprintf(stderr,
"rt_process_forms: invalid form\n");
3352 const int formid = grpt->
formid;
3353 const float form_opacity = grpt->
opacity;
3356 fprintf(stderr,
"rt_process_forms: form is null\n");
3363 fprintf(stderr,
"rt_process_forms: missing form=%i from array\n", formid);
3368 if(
p->rt_forms[index].scale != scale)
3377 fprintf(stderr,
"rt_process_forms: missing form=%i from masks\n", formid);
3392 &roi_mask.
x, &roi_mask.
y);
3395 fprintf(stderr,
"rt_process_forms: error retrieving mask\n");
3401 float dx = 0.f, dy = 0.f;
3406 p->rt_forms[index].distort_mode))
3414 float *mask_scaled = NULL;
3416 if(
rt_build_scaled_mask(mask, &roi_mask, &mask_scaled, &roi_mask_scaled, roi_layer, dx, dy, algo) != 0)
3435 && ((roi_mask_scaled.
width > 2) && (roi_mask_scaled.
height > 2)))
3439 if(
_retouch_clone(layer, roi_layer, mask_scaled, &roi_mask_scaled, dx, dy, form_opacity) != 0)
3447 if(
_retouch_heal(layer, roi_layer, mask_scaled, &roi_mask_scaled, dx, dy, form_opacity,
p->max_heal_iter) != 0)
3455 if(
_retouch_blur(self, pipe, layer, roi_layer, mask_scaled, &roi_mask_scaled, form_opacity,
3456 p->rt_forms[index].blur_type,
p->rt_forms[index].blur_radius, wt_p->
use_sse) != 0)
3469 fill_color[0] = fill_color[1] = fill_color[2] =
p->rt_forms[index].fill_brightness;
3473 fill_color[0] =
p->rt_forms[index].fill_color[0] +
p->rt_forms[index].fill_brightness;
3474 fill_color[1] =
p->rt_forms[index].fill_color[1] +
p->rt_forms[index].fill_brightness;
3475 fill_color[2] =
p->rt_forms[index].fill_color[2] +
p->rt_forms[index].fill_brightness;
3477 fill_color[3] = 0.0f;
3479 _retouch_fill(layer, roi_layer, mask_scaled, &roi_mask_scaled, form_opacity, fill_color);
3482 fprintf(stderr,
"rt_process_forms: unknown algorithm %i\n", algo);
3504 float *in_retouch = NULL;
3514 const int display_wavelet_scale = (
g && gui_active) ?
g->display_wavelet_scale : 0;
3528 usr_data.
self = self;
3529 usr_data.
pipe = pipe;
3530 usr_data.
piece = piece;
3531 usr_data.
roi = *roi_rt;
3534 && (pipe == self->
dev->
pipe));
3540 p->merge_from_scale, &usr_data,
3541 roi_in->
scale, use_sse);
3553 for(
size_t j = 0; j < (size_t)roi_rt->
width * roi_rt->
height * 4; j += 4) in_retouch[j + 3] = 0.f;
3566 if(dwt_p->
scales > max_scales)
3568 dt_control_log(_(
"max scale is %i for this image size"), max_scales);
3590 g->preview_auto_levels = -1;
3598 for(
int i = 0;
i < 3;
i++)
g->preview_levels[
i] =
levels[
i];
3601 g->preview_auto_levels = 2;
3615 dt_iop_alpha_copy(ivoid, in_retouch, roi_rt->
width, roi_rt->
height);
3636 const float *
const in,
float *
const out,
const dt_iop_roi_t *
const roi_in,
3646 const int devid, cl_mem dev_img,
const int width,
const int height,
3649 cl_int err = CL_SUCCESS;
3653 float *src_buffer = NULL;
3658 fprintf(stderr,
"dt_heal_cl: error allocating memory for healing\n");
3665 if(err != CL_SUCCESS)
3674 if(err != CL_SUCCESS)
3686 const int devid, cl_mem dev_img,
const int width,
const int height,
3689 cl_int err = CL_SUCCESS;
3693 float *src_buffer = NULL;
3698 fprintf(stderr,
"dt_heal_cl: error allocating memory for healing\n");
3705 if(err != CL_SUCCESS)
3714 if(err != CL_SUCCESS)
3726 cl_mem dev_out,
const struct dt_iop_roi_t *
const roi_out,
const int dx,
3727 const int dy,
const int kernel)
3729 cl_int err = CL_SUCCESS;
3731 const int xoffs = roi_out->
x - roi_in->
x - dx;
3732 const int yoffs = roi_out->
y - roi_in->
y - dy;
3734 cl_mem dev_roi_in = NULL;
3735 cl_mem dev_roi_out = NULL;
3737 const size_t sizes[]
3744 fprintf(stderr,
"rt_copy_in_to_out_cl error 1\n");
3745 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
3756 if(err != CL_SUCCESS)
3758 fprintf(stderr,
"rt_copy_in_to_out_cl error 2\n");
3770 float **mask_scaled, cl_mem *p_dev_mask_scaled,
3772 const int dy,
const int algo)
3774 cl_int err = CL_SUCCESS;
3782 const cl_mem dev_mask_scaled
3786 fprintf(stderr,
"rt_build_scaled_mask_cl error 2\n");
3787 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
3792 sizeof(
float) * roi_mask_scaled->
width * roi_mask_scaled->
height, CL_TRUE);
3793 if(err != CL_SUCCESS)
3795 fprintf(stderr,
"rt_build_scaled_mask_cl error 4\n");
3799 *p_dev_mask_scaled = dev_mask_scaled;
3802 if(err != CL_SUCCESS) fprintf(stderr,
"rt_build_scaled_mask_cl error\n");
3811 cl_int err = CL_SUCCESS;
3815 const cl_mem dev_roi_dest =
3818 const cl_mem dev_roi_mask_scaled
3823 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
3834 if(err != CL_SUCCESS)
goto cleanup;
3844 cl_mem dev_mask_scaled,
dt_iop_roi_t *
const roi_mask_scaled,
3847 cl_int err = CL_SUCCESS;
3854 const cl_mem dev_roi_mask_scaled
3858 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
3868 if(err != CL_SUCCESS)
goto cleanup;
3879 cl_mem dev_mask_scaled,
dt_iop_roi_t *
const roi_mask_scaled,
const int dx,
3882 cl_int err = CL_SUCCESS;
3888 sizeof(
float) *
ch * roi_mask_scaled->
width * roi_mask_scaled->
height);
3891 fprintf(stderr,
"retouch_clone_cl error 2\n");
3892 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
3899 if(err != CL_SUCCESS)
3901 fprintf(stderr,
"retouch_clone_cl error 4\n");
3906 err =
rt_copy_image_masked_cl(devid, dev_src, dev_layer, roi_layer, dev_mask_scaled, roi_mask_scaled, opacity,
3908 if(err != CL_SUCCESS)
3910 fprintf(stderr,
"retouch_clone_cl error 5\n");
3921 cl_mem dev_mask_scaled,
dt_iop_roi_t *
const roi_mask_scaled,
const float opacity,
3924 cl_int err = CL_SUCCESS;
3931 const cl_mem dev_roi_mask_scaled
3935 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
3948 if(err != CL_SUCCESS)
goto cleanup;
3959 cl_mem dev_mask_scaled,
dt_iop_roi_t *
const roi_mask_scaled,
const float opacity,
3962 cl_int err = CL_SUCCESS;
3964 if(fabsf(blur_radius) <= 0.1f)
return err;
3966 const float sigma = blur_radius * roi_layer->
scale;
3969 const cl_mem dev_dest =
3973 fprintf(stderr,
"retouch_blur_cl error 2\n");
3974 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
3987 if(err != CL_SUCCESS)
goto cleanup;
3992 if(err != CL_SUCCESS)
3994 fprintf(stderr,
"retouch_blur_cl error 4\n");
4000 float Labmax[] = { INFINITY, INFINITY, INFINITY, INFINITY };
4001 float Labmin[] = { -INFINITY, -INFINITY, -INFINITY, -INFINITY };
4009 if(err != CL_SUCCESS)
goto cleanup;
4016 const float detail = -1.0f;
4031 err =
rt_copy_image_masked_cl(devid, dev_dest, dev_layer, roi_layer, dev_mask_scaled, roi_mask_scaled, opacity,
4033 if(err != CL_SUCCESS)
4035 fprintf(stderr,
"retouch_blur_cl error 5\n");
4048 if(err != CL_SUCCESS)
goto cleanup;
4058 cl_mem dev_mask_scaled,
dt_iop_roi_t *
const roi_mask_scaled,
const int dx,
4061 cl_int err = CL_SUCCESS;
4065 cl_mem dev_dest = NULL;
4067 sizeof(
float) *
ch * roi_mask_scaled->
width * roi_mask_scaled->
height);
4070 fprintf(stderr,
"retouch_heal_cl: error allocating memory for healing\n");
4071 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
4076 sizeof(
float) *
ch * roi_mask_scaled->
width * roi_mask_scaled->
height);
4079 fprintf(stderr,
"retouch_heal_cl: error allocating memory for healing\n");
4080 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
4086 if(err != CL_SUCCESS)
4088 fprintf(stderr,
"retouch_heal_cl error 4\n");
4094 if(err != CL_SUCCESS)
4096 fprintf(stderr,
"retouch_heal_cl error 4\n");
4104 err =
dt_heal_cl(hp, dev_src, dev_dest, mask_scaled, roi_mask_scaled->
width, roi_mask_scaled->
height, max_iter);
4110 if(err != CL_SUCCESS)
goto cleanup;
4114 err =
rt_copy_image_masked_cl(devid, dev_dest, dev_layer, roi_layer, dev_mask_scaled, roi_mask_scaled, opacity,
4116 if(err != CL_SUCCESS)
4118 fprintf(stderr,
"retouch_heal_cl error 6\n");
4131 cl_int err = CL_SUCCESS;
4144 if(scale > wt_p->
scales + 1)
return err;
4149 const int devid = pipe->
devid;
4152 const int mask_display
4160 scale =
p->num_scales + 1;
4170 for(
const GList *forms = grp->
points; forms && err == CL_SUCCESS; forms = g_list_next(forms))
4175 fprintf(stderr,
"rt_process_forms: invalid form\n");
4178 const int formid = grpt->
formid;
4179 const float form_opacity = grpt->
opacity;
4182 fprintf(stderr,
"rt_process_forms: form is null\n");
4189 fprintf(stderr,
"rt_process_forms: missing form=%i from array\n", formid);
4194 if(
p->rt_forms[index].scale != scale)
4203 fprintf(stderr,
"rt_process_forms: missing form=%i from masks\n", formid);
4218 &roi_mask.
x, &roi_mask.
y);
4221 fprintf(stderr,
"rt_process_forms: error retrieving mask\n");
4225 float dx = 0.f, dy = 0.f;
4232 p->rt_forms[index].distort_mode))
4240 cl_mem dev_mask_scaled = NULL;
4241 float *mask_scaled = NULL;
4245 roi_layer, dx, dy, algo);
4264 dev_mask_scaled = NULL;
4268 if((err == CL_SUCCESS)
4270 && ((roi_mask_scaled.
width > 2) && (roi_mask_scaled.
height > 2)))
4274 err =
_retouch_clone_cl(devid, dev_layer, roi_layer, dev_mask_scaled, &roi_mask_scaled, dx, dy,
4279 err =
_retouch_heal_cl(devid, dev_layer, roi_layer, mask_scaled, dev_mask_scaled, &roi_mask_scaled, dx,
4280 dy, form_opacity, gd,
p->max_heal_iter);
4284 err =
_retouch_blur_cl(devid, dev_layer, roi_layer, dev_mask_scaled, &roi_mask_scaled, form_opacity,
4285 p->rt_forms[index].blur_type,
p->rt_forms[index].blur_radius, gd);
4294 fill_color[0] = fill_color[1] = fill_color[2] =
p->rt_forms[index].fill_brightness;
4298 fill_color[0] =
p->rt_forms[index].fill_color[0] +
p->rt_forms[index].fill_brightness;
4299 fill_color[1] =
p->rt_forms[index].fill_color[1] +
p->rt_forms[index].fill_brightness;
4300 fill_color[2] =
p->rt_forms[index].fill_color[2] +
p->rt_forms[index].fill_brightness;
4303 err =
_retouch_fill_cl(devid, dev_layer, roi_layer, dev_mask_scaled, &roi_mask_scaled, form_opacity,
4307 fprintf(stderr,
"rt_process_forms: unknown algorithm %i\n", algo);
4331 cl_int err = CL_SUCCESS;
4332 const int devid = pipe->
devid;
4342 const int display_wavelet_scale = (
g && gui_active) ?
g->display_wavelet_scale : 0;
4349 dt_print(
DT_DEBUG_OPENCL,
"[retouch process_cl] error allocating memory for wavelet decompose on device %d\n", devid);
4350 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
4356 size_t origin[] = { 0, 0, 0 };
4357 size_t region[] = { roi_rt->
width, roi_rt->
height, 1 };
4359 if(err != CL_SUCCESS)
goto cleanup;
4363 usr_data.
self = self;
4364 usr_data.
pipe = pipe;
4365 usr_data.
piece = piece;
4366 usr_data.
roi = *roi_rt;
4369 && (pipe == self->
dev->
pipe));
4374 (!display_wavelet_scale
4376 p->merge_from_scale, &usr_data,
4381 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
4402 if(err != CL_SUCCESS)
goto cleanup;
4415 if(dwt_p->
scales > max_scales)
4417 dt_control_log(_(
"max scale is %i for this image size"), max_scales);
4426 if(err != CL_SUCCESS)
goto cleanup;
4436 g->preview_auto_levels = -1;
4442 if(err != CL_SUCCESS)
goto cleanup;
4446 for(
int i = 0;
i < 3;
i++)
g->preview_levels[
i] =
levels[
i];
4449 g->preview_auto_levels = 2;
4458 if(err != CL_SUCCESS)
goto cleanup;
4472 if(err != CL_SUCCESS)
goto cleanup;
4486 return (err == CL_SUCCESS) ?
TRUE :
FALSE;
4497 const int formid = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
"formid"));
4498 const int algo = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
"algo"));
4500 if(index < 0)
return;
4502 if(
p->rt_forms[index].algorithm == algo)
return;
4507 p->rt_forms[index].algorithm = algo;
4514 masks_type &= ~DT_MASKS_NON_CLONE;
4518 masks_type &= ~DT_MASKS_CLONE;
4521 form->
type = masks_type;
4535 fprintf(stderr,
"populate_masks_context_menu: missing form=%i from array\n", formid);
4541 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), sub_menu);
4552 for(
size_t i = 0;
i < G_N_ELEMENTS(algo_entries);
i++)
4554 const gboolean is_selected = (
p->rt_forms[index].algorithm == algo_entries[
i].algo);
4555 const char *
const label = _(algo_entries[
i].
name);
4558 is_selected,
FALSE);
4560 g_object_set_data(G_OBJECT(algo_item),
"formid", GINT_TO_POINTER(formid));
4561 g_object_set_data(G_OBJECT(algo_item),
"algo", GINT_TO_POINTER(algo_entries[
i].algo));
Handle default and user-set shortcuts (accelerators)
void cleanup(dt_imageio_module_format_t *self)
int levels(struct dt_imageio_module_data_t *data)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
float dt_bauhaus_slider_get(GtkWidget *widget)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int 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_slider_set_format(GtkWidget *widget, const char *format)
void dt_bilateral_free(dt_bilateral_t *b)
__DT_CLONE_TARGETS__ void dt_bilateral_splat(const dt_bilateral_t *b, const float *const in)
dt_bilateral_t * dt_bilateral_init(const int width, const int height, const float sigma_s, const float sigma_r)
__DT_CLONE_TARGETS__ void dt_bilateral_slice(const dt_bilateral_t *const b, const float *const in, float *out, const float detail)
void dt_bilateral_blur(const dt_bilateral_t *b)
void dt_bilateral_free_cl(dt_bilateral_cl_t *b)
cl_int dt_bilateral_slice_cl(dt_bilateral_cl_t *b, cl_mem in, cl_mem out, const float detail)
dt_bilateral_cl_t * dt_bilateral_init_cl(const int devid, const int width, const int height, const float sigma_s, const float sigma_r)
cl_int dt_bilateral_blur_cl(dt_bilateral_cl_t *b)
cl_int dt_bilateral_splat_cl(dt_bilateral_cl_t *b, cl_mem in)
const dt_iop_gui_blendif_colorstop_t _gradient_L[]
The blending panel's GUI state and API, cut out of develop/blend.h.
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
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)
void dt_colorspaces_apply_profile(const char *const op_name, const char *const instance_name, const float *const image_in, float *const image_out, const int width, const int height, const int cst_from, const int cst_to, int *converted_cst, const dt_iop_order_iccprofile_info_t *const profile_info)
Convert a 4-channel float buffer between RGB and Lab through one profile.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
static const float const float const float min
static dt_aligned_pixel_t XYZ
static dt_aligned_pixel_t Lab
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_conf_set_float(const char *name, float val)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
void dt_control_log(const char *msg,...)
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_update_history_main(dev)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_work_profile_info(const struct dt_dev_pixelpipe_t *pipe)
int dt_dev_distort_transform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
dt_dev_pixelpipe_display_mask_t
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
@ DT_DEV_PIXELPIPE_DISPLAY_PASSTHRU
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
@ DT_DEV_TRANSFORM_DIR_BACK_INCL
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_rdlock(dt_pthread_rwlock_t *rwlock) ACQUIRE_SHARED(rwlock) NO_THREAD_SAFETY_ANALYSIS
int dt_dwt_first_scale_visible_cl(dwt_params_cl_t *p)
int dwt_decompose(dwt_params_t *p, _dwt_layer_func layer_func)
int dwt_get_max_scale(dwt_params_t *p)
void dt_dwt_free(dwt_params_t *p)
dwt_params_cl_t * dt_dwt_init_cl(const int devid, cl_mem image, const int width, const int height, const int scales, const int return_layer, const int merge_from_scale, void *user_data, const float preview_scale)
void dt_dwt_free_cl(dwt_params_cl_t *p)
dwt_params_t * dt_dwt_init(float *image, const int width, const int height, const int ch, const int scales, const int return_layer, const int merge_from_scale, void *user_data, const float preview_scale, const int use_sse)
cl_int dwt_decompose_cl(dwt_params_cl_t *p, _dwt_layer_func_cl layer_func)
int dwt_get_max_scale_cl(dwt_params_cl_t *p)
int dt_dwt_first_scale_visible(dwt_params_t *p)
void dt_gaussian_free(dt_gaussian_t *g)
void dt_gaussian_free_cl(dt_gaussian_cl_t *g)
cl_int dt_gaussian_blur_cl(dt_gaussian_cl_t *g, cl_mem dev_in, cl_mem dev_out)
void dt_gaussian_blur_4c(dt_gaussian_t *g, const float *const in, float *const out)
dt_gaussian_cl_t * dt_gaussian_init_cl(const int devid, const int width, const int height, const int channels, const float *max, const float *min, const float sigma, const int order)
dt_gaussian_t * dt_gaussian_init(const int width, const int height, const int channels, const float *max, const float *min, const float sigma, const int order)
void dtgtk_gradient_slider_multivalue_set_values(GtkDarktableGradientSlider *gslider, gdouble *values)
void dtgtk_gradient_slider_multivalue_get_values(GtkDarktableGradientSlider *gslider, gdouble *values)
GtkWidget * dtgtk_gradient_slider_multivalue_new_with_color_and_name(GdkRGBA start, GdkRGBA end, gint positions, gchar *name)
void dtgtk_gradient_slider_multivalue_set_marker(GtkDarktableGradientSlider *gslider, gint mark, gint pos)
void dtgtk_gradient_slider_multivalue_set_resetvalues(GtkDarktableGradientSlider *gslider, gdouble *values)
#define DTGTK_GRADIENT_SLIDER_MULTIVALUE(obj)
@ GRADIENT_SLIDER_MARKER_LOWER_OPEN_BIG
@ GRADIENT_SLIDER_MARKER_LOWER_FILLED_BIG
void dt_heal_free_cl(heal_params_cl_t *p)
void dt_heal(const float *const src_buffer, float *dest_buffer, const float *const mask_buffer, const int width, const int height, const int ch, const int max_iter)
cl_int dt_heal_cl(heal_params_cl_t *p, cl_mem dev_src, cl_mem dev_dest, const float *const mask_buffer, const int width, const int height, const int max_iter)
heal_params_cl_t * dt_heal_init_cl(const int devid)
float dt_boundingbox_t[4]
__DT_CLONE_TARGETS__ void dt_iop_image_fill(float *const buf, const float fill_value, const size_t width, const size_t height, const size_t ch)
static void dt_iop_image_copy_by_size(float *const __restrict__ out, const float *const __restrict__ in, const size_t width, const size_t height, const size_t ch)
void dt_iop_set_cache_bypass_variant(dt_iop_module_t *module, int variant)
void dt_iop_default_init(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)
void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module)
Release what dt_iop_gui_enter_critical_section() took. Also a no-op headless.
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
@ IOP_FLAGS_INTERNAL_MASKS
@ IOP_FLAGS_SUPPORTS_BLENDING
void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module)
Take the module's GUI lock, serialising access to its dt_iop_gui_data_t.
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)
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
#define IOP_GUI_ALLOC(module)
static float kernel(const float *x, const float *y)
GtkWidget * dt_ui_section_label_new(const gchar *str)
GtkWidget * dt_ui_label_new(const gchar *str)
_lib_location_type_t type
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
dt_masks_result_t dt_masks_group_set_member_opacity(dt_develop_t *dev, const int group_id, const int formid, const float opacity, dt_masks_member_t *out)
Set a group member's opacity.
dt_masks_raster_result_t dt_masks_get_source_area(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, int *width, int *height, int *posx, int *posy)
dt_masks_raster_result_t dt_masks_get_mask(const dt_iop_module_t *const module, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *const piece, dt_masks_form_t *const form, float **buffer, int *width, int *height, int *posx, int *posy)
dt_masks_form_t * dt_masks_create_ext(dt_develop_t *dev, dt_masks_type_t type)
dt_masks_form_t * dt_masks_get_from_id_ext(GList *forms, int id)
dt_masks_form_t * dt_masks_get_from_id(dt_develop_t *dev, int id)
dt_masks_raster_result_t dt_masks_get_area(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, int *width, int *height, int *posx, int *posy)
void dt_masks_set_edit_mode(struct dt_iop_module_t *module, dt_masks_edit_mode_t value)
Ask the masks module about a shape or a group, instead of reading its structs.
void dt_masks_group_ungroup(dt_develop_t *dev, dt_masks_form_t *dest_group, dt_masks_form_t *group_form)
void dt_masks_change_form_gui(dt_develop_t *dev, dt_masks_form_t *new_form)
dt_masks_form_group_t * dt_masks_form_get_selected_group_live(const dt_masks_form_t *mask_form, const dt_masks_form_gui_t *mask_gui)
Resolve a "live" selected group entry, even if GUI selection is stale.
void dt_masks_shape_buttons_deactivate_all(GtkWidget *active_button)
GtkWidget * dt_masks_shape_buttons_create(const dt_masks_shape_buttons_config_t *config)
Build a synchronized toolbar for creating masks shapes.
dt_masks_form_t * dt_masks_get_visible_form(const dt_develop_t *dev)
Return the currently visible form used by the masks GUI.
void dt_masks_reset_form_gui(dt_develop_t *dev)
gboolean dt_masks_creation_mode_enter(dt_develop_t *dev, dt_iop_module_t *module, const dt_masks_type_t type)
Enter mask creation mode for a given shape type.
dt_masks_form_group_t * dt_masks_group_add_form_with_state(dt_develop_t *dev, dt_masks_form_t *group_form, dt_masks_form_t *mask_form, const int parentid, const dt_masks_state_t state, const float opacity)
The interactive half of the masks subsystem: the editing state (dt_masks_form_gui_t),...
@ DT_MASKS_SHAPE_INDEX_BRUSH
@ DT_MASKS_SHAPE_INDEX_ELLIPSE
@ DT_MASKS_SHAPE_INDEX_CIRCLE
@ DT_MASKS_SHAPE_INDEX_POLYGON
@ DT_MASKS_SHAPE_BUTTONS_ALL
@ DT_MASKS_EDIT_RESTRICTED
dt_masks_result_t
What a request that may change the masks model did.
#define DEVELOP_MASKS_NB_SHAPES
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
int dt_opencl_create_kernel(const int prog, const char *name)
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
int dt_opencl_write_buffer_to_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
int dt_opencl_read_buffer_from_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
void dt_opencl_free_kernel(const int kernel)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
int dt_opencl_enqueue_copy_image_to_buffer(const int devid, cl_mem src_image, cl_mem dst_buffer, size_t *origin, size_t *region, size_t offset)
void dt_opencl_release_mem_object(cl_mem mem)
#define DT_OPENCL_SYSMEM_ALLOCATION
#define __OMP_PARALLEL_FOR__(...)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
static cl_int _retouch_heal_cl(const int devid, cl_mem dev_layer, dt_iop_roi_t *const roi_layer, float *mask_scaled, cl_mem dev_mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const int dx, const int dy, const float opacity, dt_iop_retouch_global_data_t *gd, const int max_iter)
static gboolean rt_shape_buttons_can_start(GtkWidget *button, dt_iop_module_t *self, dt_masks_type_t type, gpointer user_data)
static cl_int rt_build_scaled_mask_cl(const int devid, float *const mask, dt_iop_roi_t *const roi_mask, float **mask_scaled, cl_mem *p_dev_mask_scaled, dt_iop_roi_t *roi_mask_scaled, dt_iop_roi_t *const roi_in, const int dx, const int dy, const int algo)
static int rt_masks_get_delta_to_destination(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi, dt_masks_form_t *form, float *dx, float *dy, const int distort_mode)
static dt_masks_type_t rt_shape_buttons_form_type(dt_iop_module_t *self, dt_masks_type_t type, gpointer user_data)
dt_iop_retouch_fill_modes_t
@ DT_IOP_RETOUCH_FILL_COLOR
@ DT_IOP_RETOUCH_FILL_ERASE
static float rt_gslider_scale_callback(GtkWidget *self, float inval, int dir)
static void rt_copy_mask_to_alpha(float *const img, dt_iop_roi_t *const roi_img, const int ch, float *const mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const float opacity)
void init(dt_iop_module_t *module)
static void rt_num_scales_update(const int _num_scales, dt_iop_module_t *self)
void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const float *const in, float *const out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
static void rt_resynch_params(struct dt_iop_module_t *self, dt_iop_retouch_params_t *p, GList *forms_list)
const char ** description(struct dt_iop_module_t *self)
static cl_int rt_copy_mask_to_alpha_cl(const int devid, cl_mem dev_layer, dt_iop_roi_t *const roi_layer, cl_mem dev_mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const float opacity, dt_iop_retouch_global_data_t *gd)
static void rt_extend_roi_in_for_clone(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *const pipe, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_in, int *_roir, int *_roib, int *_roix, int *_roiy)
static float rt_get_shape_opacity(dt_iop_module_t *self, const int formid)
static int _retouch_clone(float *const in, dt_iop_roi_t *const roi_in, float *const mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const int dx, const int dy, const float opacity)
static void rt_menu_select_algorithm_callback(GtkWidget *widget, gpointer user_data)
static gboolean rt_select_algorithm_callback(GtkToggleButton *togglebutton, GdkEventButton *e, dt_iop_module_t *self)
dt_iop_retouch_algo_type_t
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static cl_int _retouch_blur_cl(const int devid, cl_mem dev_layer, dt_iop_roi_t *const roi_layer, cl_mem dev_mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const float opacity, const int blur_type, const float blur_radius, dt_iop_retouch_global_data_t *gd)
void masks_selection_changed(struct dt_iop_module_t *self, const int form_selected_id)
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
cl_int rt_process_stats_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const int devid, cl_mem dev_img, const int width, const int height, float levels[3])
dt_iop_retouch_drag_types_t
@ DT_IOP_RETOUCH_WDBAR_DRAG_BOTTOM
@ DT_IOP_RETOUCH_WDBAR_DRAG_TOP
static float rt_masks_form_get_opacity(dt_iop_module_t *self, int formid)
static void image_lab2rgb(float *img_src, const int width, const int height, const int ch, const int use_sse)
struct dt_iop_retouch_params_t dt_iop_retouch_data_t
static void rt_merge_from_scale_update(const int _merge_from_scale, dt_iop_module_t *self)
static void rt_sync_mask_display_request(dt_iop_module_t *module, dt_iop_retouch_gui_data_t *g)
static cl_int rt_copy_image_masked_cl(const int devid, cl_mem dev_src, cl_mem dev_dest, dt_iop_roi_t *const roi_dest, cl_mem dev_mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const float opacity, const int kernel)
void gui_focus(struct dt_iop_module_t *self, gboolean in)
#define RETOUCH_MAX_SCALES
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static gboolean rt_edit_masks_callback(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self)
static int rt_get_selected_shape_id(const dt_iop_module_t *self)
static dt_masks_form_group_t * rt_get_mask_point_group(dt_iop_module_t *self, int formid)
static gboolean rt_wdbar_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self)
void gui_reset(struct dt_iop_module_t *self)
static cl_int _retouch_clone_cl(const int devid, cl_mem dev_layer, dt_iop_roi_t *const roi_layer, cl_mem dev_mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const int dx, const int dy, const float opacity, dt_iop_retouch_global_data_t *gd)
static cl_int rt_copy_in_to_out_cl(const int devid, cl_mem dev_in, const struct dt_iop_roi_t *const roi_in, cl_mem dev_out, const struct dt_iop_roi_t *const roi_out, const int dx, const int dy, const int kernel)
static void rt_develop_ui_pipe_finished_callback(gpointer instance, gpointer user_data)
static gboolean rt_any_preview_active(dt_iop_retouch_gui_data_t *g)
void gui_init(dt_iop_module_t *self)
void change_image(struct dt_iop_module_t *self)
static void image_rgb2lab(float *img_src, const int width, const int height, const int ch, const int use_sse)
static void rt_display_selected_shapes_lbl(dt_develop_t *dev, dt_iop_retouch_gui_data_t *g)
static __DT_CLONE_TARGETS__ int process_internal(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const int use_sse)
static __DT_CLONE_TARGETS__ void rt_adjust_levels(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, float *img_src, const int width, const int height, const int ch, const float levels[3])
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
#define RETOUCH_NO_SCALES
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
static gboolean rt_masks_form_is_in_roi(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out)
static int rt_shape_is_being_added(dt_iop_module_t *self, const int shape_type)
static gboolean rt_wdbar_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self)
void gui_cleanup(dt_iop_module_t *self)
static cl_int rt_process_forms_cl(cl_mem dev_layer, dwt_params_cl_t *const wt_p, const int scale1)
dt_iop_retouch_blur_types_t
@ DT_IOP_RETOUCH_BLUR_GAUSSIAN
@ DT_IOP_RETOUCH_BLUR_BILATERAL
static __DT_CLONE_TARGETS__ void rt_copy_in_to_out(const float *const in, const struct dt_iop_roi_t *const roi_in, float *const out, const struct dt_iop_roi_t *const roi_out, const int ch, const int dx, const int dy)
void cleanup_global(dt_iop_module_so_t *module)
void reload_defaults(dt_iop_module_t *self)
static gboolean rt_wdbar_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self)
void post_history_commit(dt_iop_module_t *self)
static gboolean rt_algo_pair_compatible(const dt_iop_retouch_algo_type_t from, const dt_iop_retouch_algo_type_t to)
static gboolean rt_suppress_callback(GtkToggleButton *togglebutton, GdkEventButton *event, dt_iop_module_t *module)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
static void rt_gslider_changed(GtkDarktableGradientSlider *gslider, dt_iop_module_t *self)
#define RETOUCH_PREVIEW_LVL_MIN
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)
static void rt_show_forms_for_current_scale(dt_iop_module_t *self)
static void rt_show_hide_controls(const dt_iop_module_t *self)
static void rt_colorpick_color_set_callback(GtkColorButton *widget, dt_iop_module_t *self)
static void _retouch_fill(float *const in, dt_iop_roi_t *const roi_in, float *const mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const float opacity, const float *const fill_color)
static void rt_copy_image_masked(float *const img_src, float *img_dest, dt_iop_roi_t *const roi_dest, float *const mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const float opacity)
static cl_int _retouch_fill_cl(const int devid, cl_mem dev_layer, dt_iop_roi_t *const roi_layer, cl_mem dev_mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const float opacity, float *color, dt_iop_retouch_global_data_t *gd)
static void rt_masks_point_denormalize(const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi, const float *points, size_t points_count, float *new)
static gboolean rt_wdbar_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self)
static void rt_sync_bypass_cache(dt_iop_module_t *module, dt_iop_retouch_gui_data_t *g)
static int rt_scale_has_shapes(dt_iop_retouch_params_t *p, const int scale)
int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
static gboolean rt_wdbar_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self)
static gboolean rt_blend_mask_conflicts(dt_iop_module_t *module, dt_iop_retouch_gui_data_t *g)
static int rt_process_forms(float *layer, dwt_params_t *const wt_p, const int scale1)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void rt_compute_roi_in(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *const pipe, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_in, int *_roir, int *_roib, int *_roix, int *_roiy)
static gboolean rt_showmask_callback(GtkToggleButton *togglebutton, GdkEventButton *event, dt_iop_module_t *module)
static void rt_load_shape_algo_in_gui(dt_iop_module_t *self, const int form_selected_id)
static int rt_get_index_from_formid(dt_iop_retouch_params_t *p, const int formid)
cl_int rt_adjust_levels_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const int devid, cl_mem dev_img, const int width, const int height, const float levels[3])
static void rt_curr_scale_update(const int _curr_scale, dt_iop_module_t *self)
static __DT_CLONE_TARGETS__ void rt_process_stats(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, float *const img_src, const int width, const int height, const int ch, float levels[3])
static void rt_update_wd_bar_labels(dt_iop_retouch_params_t *p, dt_iop_retouch_gui_data_t *g)
void init_global(dt_iop_module_so_t *module)
static int _retouch_blur(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, float *const in, dt_iop_roi_t *const roi_in, float *const mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const float opacity, const int blur_type, const float blur_radius, const int use_sse)
static gboolean rt_auto_levels_callback(GtkToggleButton *togglebutton, GdkEventButton *event, dt_iop_module_t *self)
static void rt_mask_opacity_callback(GtkWidget *slider, dt_iop_module_t *self)
static void rt_display_selected_fill_color(dt_iop_retouch_gui_data_t *g, dt_iop_retouch_params_t *p)
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
static void rt_intersect_2_rois(dt_iop_roi_t *const roi_1, dt_iop_roi_t *const roi_2, const int dx, const int dy, const int padding, dt_iop_roi_t *roi_dest)
static int rt_get_selected_shape_index(dt_develop_t *dev, dt_iop_retouch_params_t *p)
static gboolean rt_copypaste_scale_callback(GtkToggleButton *togglebutton, GdkEventButton *event, dt_iop_module_t *self)
static gboolean rt_wdbar_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self)
static int _retouch_heal(float *const in, dt_iop_roi_t *const roi_in, float *const mask_scaled, dt_iop_roi_t *const roi_mask_scaled, const int dx, const int dy, const float opacity, const int max_iter)
static int rt_allow_create_form(dt_iop_module_t *self)
int populate_masks_context_menu(struct dt_iop_module_t *self, GtkWidget *menu, const int formid, const float pzx, const float pzy)
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static int rt_build_scaled_mask(float *const mask, dt_iop_roi_t *const roi_mask, float **mask_scaled, dt_iop_roi_t *roi_mask_scaled, dt_iop_roi_t *const roi_in, const int dx, const int dy, const int algo)
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)
static gboolean rt_display_wavelet_scale_callback(GtkToggleButton *togglebutton, GdkEventButton *event, dt_iop_module_t *self)
#define RETOUCH_PREVIEW_LVL_MAX
void modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out, const 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)
static void rt_extend_roi_in_from_source_clones(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *const pipe, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_in, const int formid_src, const int fl_src, const int ft_src, const int fw_src, const int fh_src, int *_roir, int *_roib, int *_roix, int *_roiy)
static void rt_masks_form_change_opacity(dt_iop_module_t *self, int formid, float opacity)
static void rt_paste_forms_from_scale(dt_iop_retouch_params_t *p, const int source_scale, const int dest_scale)
static int rt_masks_point_calc_delta(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi, const float *target, const float *source, float *dx, float *dy, const int distort_mode)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ 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)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
#define for_each_channel(_var,...)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
struct dt_iop_module_t * gui_module
struct dt_masks_form_gui_t * form_gui
dt_pthread_rwlock_t masks_mutex
struct dt_dev_pixelpipe_t * pipe
dt_iop_global_data_t * data
dt_iop_params_t * default_params
struct dt_develop_blend_params_t * blend_params
struct dt_iop_module_gui_t * gui
struct dt_develop_t * dev
dt_iop_global_data_t * global_data
dt_aligned_pixel_t picked_output_color
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
int nonlinearlut
Non-zero when the profile has tone curves at all; tested as a boolean everywhere, but it is really th...
int lutsize
Entry count of each of the six LUTs. Always 65536 in practice: both callers of dt_ioppr_init_profile_...
dt_colormatrix_t matrix_out_transposed
float * lut_out[3]
Per-channel linear -> encoded tone curve, same convention as lut_in.
float * lut_in[3]
Per-channel encoded -> linear tone curve, lutsize entries each, sampled over [0,1]....
dt_colormatrix_t matrix_in_transposed
int kernel_retouch_copy_alpha
int kernel_retouch_clear_alpha
int kernel_retouch_copy_buffer_to_buffer_masked
int kernel_retouch_copy_image_to_buffer_masked
int kernel_retouch_image_rgb2lab
int kernel_retouch_image_lab2rgb
int kernel_retouch_copy_mask_to_alpha
int kernel_retouch_copy_buffer_to_image
int kernel_retouch_copy_buffer_to_buffer
GtkDarktableGradientSlider * preview_levels_gslider
int display_wavelet_scale
GtkWidget * cmb_blur_type
GtkWidget * bt_paste_scale
GtkWidget * sl_fill_brightness
GtkWidget * hbox_color_pick
GtkWidget * cmb_fill_mode
GtkWidget * sl_blur_radius
GtkWidget * vbox_preview_scale
GtkWidget * sl_mask_opacity
GtkWidget * bt_edit_masks
GtkLabel * label_form_selected
GtkWidget * bt_display_wavelet_scale
GtkWidget * bt_auto_levels
GtkLabel * lbl_num_scales
int displayed_wavelet_scale
GtkLabel * lbl_curr_scale
GtkWidget * bt_copy_scale
GtkLabel * lbl_merge_from_scale
dt_iop_retouch_blur_types_t blur_type
dt_iop_retouch_fill_modes_t fill_mode
dt_iop_retouch_algo_type_t algorithm
dt_iop_retouch_form_data_t rt_forms[300]
Region of interest passed through the pixelpipe.
One shape's membership of one group, BY VALUE.
const dt_dev_pixelpipe_t * pipe
const dt_dev_pixelpipe_iop_t * piece
#define __DT_CLONE_TARGETS__