83 return _(
"spot removal");
88 return _(
"this module is deprecated. please use the retouch module instead.");
95 _(
"linear, RGB, scene-referred"),
97 _(
"linear, RGB, scene-referred"));
116 void *new_params,
const int new_version)
118 if(old_version == 1 && new_version == 2)
120 typedef struct dt_iop_spots_v1_t
126 typedef struct dt_iop_spots_params_v1_t
129 dt_iop_spots_v1_t spot[32];
130 } dt_iop_spots_params_v1_t;
132 dt_iop_spots_params_v1_t *o = (dt_iop_spots_params_v1_t *)old_params;
137 for(
int i = 0;
i < o->num_spots;
i++)
146 circle->
center[0] = o->spot[
i].x;
147 circle->
center[1] = o->spot[
i].y;
148 circle->
radius = o->spot[
i].radius;
151 form->
source[0] = o->spot[
i].xc;
152 form->
source[1] = o->spot[
i].yc;
161 n->clone_algo[
i] = 2;
166 int last_spot_num = 0;
168 for(GList *l = self->
dev->
history; l; l = g_list_next(l))
172 if(!strcmp(item->
op_name,
"spots")) last_spot_num = item->
num;
175 if(last_spot_num == 0) last_spot_num = count;
182 for(GList *l = self->
dev->
forms; l; l = g_list_next(l))
204 int nalgo[64] = { 2 };
211 for(GList *forms = grp->
points; (
i < 64) && forms; forms = g_list_next(forms))
215 for(
int j = 0; j < 64; j++)
217 if(
p->clone_id[j] == nid[
i])
219 nalgo[
i] =
p->clone_algo[j];
228 for(
int i = 0;
i < 64;
i++)
230 p->clone_algo[
i] = nalgo[
i];
231 p->clone_id[
i] = nid[
i];
247 dt_control_log(_(
"spot module is limited to 64 shapes. please add a new instance !"));
251 && (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
g->bt_path))
252 || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
g->bt_circle))
253 || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
g->bt_ellipse))))
258 if(widget !=
g->bt_path || nb >= 64) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_path),
FALSE);
259 if(widget !=
g->bt_circle || nb >= 64) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_circle),
FALSE);
260 if(widget !=
g->bt_ellipse || nb >= 64) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_ellipse),
FALSE);
262 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
FALSE);
296 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
off),
TRUE);
303 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
return FALSE;
310 if(widget ==
g->bt_path)
312 else if(widget ==
g->bt_circle)
314 else if(widget ==
g->bt_ellipse)
359 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_path),
FALSE);
360 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_circle),
FALSE);
361 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_ellipse),
FALSE);
375 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
380 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
FALSE);
403 if(ft >= roi_out->
y + roi_out->
height || ft + fh <= roi_out->y || fl >= roi_out->
x + roi_out->
width
404 || fl + fw <= roi_out->
x)
425 int roir = roi_in->
width + roi_in->
x;
426 int roib = roi_in->
height + roi_in->
y;
427 int roix = roi_in->
x;
428 int roiy = roi_in->
y;
436 for(
const GList *forms = grp->
points; forms; forms = g_list_next(forms))
444 if(!masks_form_is_in_roi(self, processing_pipe, piece, form, roi_in, roi_out))
459 roiy = fminf(ft, roiy);
460 roix = fminf(fl, roix);
461 roir = fmaxf(fl + fw, roir);
462 roib = fmaxf(ft + fh, roib);
469 roi_in->
x = CLAMP(roix, 0, scwidth - 1);
470 roi_in->
y = CLAMP(roiy, 0, scheight - 1);
471 roi_in->
width = CLAMP(roir - roi_in->
x, 1, scwidth + .5f - roi_in->
x);
472 roi_in->
height = CLAMP(roib - roi_in->
y, 1, scheight + .5f - roi_in->
y);
477 const float *points,
size_t points_count,
float *
new)
481 for(
size_t i = 0;
i < points_count * 2;
i += 2)
483 new[
i] = points[
i] * scalex;
484 new[
i + 1] = points[
i + 1] * scaley;
489 const dt_iop_roi_t *roi,
const float *target,
const float *source,
int *dx,
499 *dx = points[0] - points[2];
500 *dy = points[1] - points[3];
515 res = masks_point_calc_delta(self, pipe, roi, pt->node, form->
source, dx, dy);
521 res = masks_point_calc_delta(self, pipe, roi, pt->center, form->
source, dx, dy);
527 res = masks_point_calc_delta(self, pipe, roi, pt->center, form->
source, dx, dy);
535 const float *
const in,
545 float *outb =
out + (size_t)
ch *
k * roi_out->
width;
546 const float *inb = in + (size_t)
ch * roi_in->
width * (
k + roi_out->
y - roi_in->
y)
547 +
ch * (roi_out->
x - roi_in->
x);
548 memcpy(outb, inb,
sizeof(
float) * roi_out->
width *
ch);
556 for(
const GList *forms = grp->
points; (pos < 64) && forms; pos++, forms = g_list_next(forms))
567 if(!masks_form_is_in_roi(self, pipe, piece, form, roi_in, roi_out))
590 const int rad =
MIN(radf[0], radf[1]);
591 const int posx = points[0] - rad;
592 const int posy = points[1] - rad;
593 const int posx_source = points[2] - rad;
594 const int posy_source = points[3] - rad;
595 const int dx = posx - posx_source;
596 const int dy = posy - posy_source;
597 const int fw = 2 * rad, fh = 2 * rad;
599 float *filter = malloc(
sizeof(
float) * (2 * rad + 1));
604 for(
int k = -rad;
k <= rad;
k++)
606 const float kk = 1.0f - fabsf(
k / (
float)rad);
607 filter[rad +
k] = kk * kk * (3.0f - 2.0f * kk);
615 for(
int yy = posy; yy < posy + fh; yy++)
618 if(yy < roi_out->y || yy >= roi_out->
y + roi_out->
height)
continue;
620 if(yy - dy < roi_in->y || yy - dy >= roi_in->
y + roi_in->
height)
continue;
621 for(
int xx = posx; xx < posx + fw; xx++)
624 if(xx < roi_out->
x || xx >= roi_out->
x + roi_out->
width)
continue;
626 if(xx - dx < roi_in->
x || xx - dx >= roi_in->
x + roi_in->
width)
continue;
628 const float f = filter[xx - posx + 1] * filter[yy - posy + 1];
629 for(
int c = 0; c <
ch; c++)
630 out[
ch * ((
size_t)roi_out->
width * (yy - roi_out->
y) + xx - roi_out->
x) + c]
631 =
out[
ch * ((size_t)roi_out->
width * (yy - roi_out->
y) + xx - roi_out->
x) + c] * (1.0f -
f)
632 + in[
ch * ((size_t)roi_in->
width * (yy - posy + posy_source - roi_in->
y) + xx - posx
633 + posx_source - roi_in->
x) + c] *
f;
653 const int fts = posy * roi_in->
scale;
655 const int fls = posx * roi_in->
scale;
660 if(!masks_get_delta(self, pipe, roi_in, form, &dx, &dy))
666 if(dx != 0 || dy != 0)
669 for(
int yy = fts + 1; yy < fts + fhs - 1; yy++)
672 if(yy < roi_out->y || yy >= roi_out->
y + roi_out->
height)
continue;
674 if(yy - dy < roi_in->y || yy - dy >= roi_in->
y + roi_in->
height)
continue;
675 for(
int xx = fls + 1; xx < fls + fws - 1; xx++)
678 if(xx < roi_out->
x || xx >= roi_out->
x + roi_out->
width)
continue;
680 if(xx - dx < roi_in->
x || xx - dx >= roi_in->
x + roi_in->
width)
continue;
682 const float f = mask[((int)((yy - fts) / roi_in->
scale)) *
width
685 for(
int c = 0; c <
ch; c++)
686 out[
ch * ((
size_t)roi_out->
width * (yy - roi_out->
y) + xx - roi_out->
x) + c]
687 =
out[
ch * ((size_t)roi_out->
width * (yy - roi_out->
y) + xx - roi_out->
x) + c] * (1.0f -
f)
688 + in[
ch * ((size_t)roi_in->
width * (yy - dy - roi_in->
y) + xx - dx - roi_in->
x) + c] *
f;
703 const float *in = (
float *)
i;
704 float *
out = (
float *)o;
709 const float *
const in,
float *
const out,
const dt_iop_roi_t *
const roi_in,
713 if(
_process(self, pipe, piece, in,
out, roi_in, roi_out, 1))
return;
720 module->global_data = NULL;
721 module->params = calloc(1, sizeof(dt_iop_spots_params_t));
722 module->default_params = calloc(1, sizeof(dt_iop_spots_params_t));
725 module->default_enabled = 0;
726 module->params_size = sizeof(dt_iop_spots_params_t);
727 module->gui_data = NULL;
752 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
758 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
FALSE);
766 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_path),
FALSE);
767 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_circle),
FALSE);
768 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_ellipse),
FALSE);
769 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
FALSE);
803 gchar *str = g_strdup_printf(
"%d", nb);
804 gtk_label_set_text(
g->label, str);
818 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
823 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->bt_edit_masks),
FALSE);
837 gtk_widget_set_tooltip_text(hbox, _(
"click on a shape and drag on canvas.\nuse the mouse wheel "
838 "to adjust size.\nright click to remove a shape."));
856 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(
g->label),
FALSE,
TRUE, 0);
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
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...
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
float dt_boundingbox_t[4]
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 dt_pixelpipe_cache_free_align(mem)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
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_TRANSFORM_DIR_BACK_INCL
void dtgtk_cairo_paint_masks_circle(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_masks_ellipse(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
Paint a 45 deg-rotated ellipse that touches the unit square boundaries.
void dtgtk_cairo_paint_masks_polygon(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_masks_edit(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
#define DT_GUI_BOX_SPACING
static GtkWidget * dt_ui_label_new(const gchar *str)
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)
@ IOP_FLAGS_INTERNAL_MASKS
@ IOP_FLAGS_SUPPORTS_BLENDING
#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)
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
int dt_masks_legacy_params(dt_develop_t *dev, void *params, const int old_version, const int new_version)
void dt_masks_change_form_gui(dt_masks_form_t *newform)
void dt_masks_reset_form_gui(void)
void dt_masks_write_masks_history_item(const int32_t imgid, const int num, dt_masks_form_t *form)
void dt_masks_gui_form_save_creation(dt_develop_t *dev, struct dt_iop_module_t *module, dt_masks_form_t *form, dt_masks_form_gui_t *gui)
Save the form creation right after a shape has been finished drawing.
int dt_masks_version(void)
dt_masks_form_t * dt_masks_create(dt_masks_type_t type)
gboolean dt_masks_creation_mode_enter(dt_iop_module_t *module, const dt_masks_type_t type)
Enter mask creation mode for a given shape type.
dt_masks_form_t * dt_masks_get_from_id(dt_develop_t *dev, int id)
static int 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)
int 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_form_t * dt_masks_get_visible_form(const struct dt_develop_t *dev)
void dt_masks_set_edit_mode(struct dt_iop_module_t *module, dt_masks_edit_mode_t value)
int 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)
struct _GtkWidget GtkWidget
void init(dt_iop_module_t *module)
const char ** description(struct dt_iop_module_t *self)
int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
static gboolean _add_shape(GtkWidget *widget, dt_iop_module_t *self)
static void _resynch_params(struct dt_iop_module_t *self)
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)
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
void distort_mask(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, 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)
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)
void gui_reset(struct dt_iop_module_t *self)
static gboolean _add_shape_callback(GtkWidget *widget, GdkEventButton *e, dt_iop_module_t *self)
void gui_init(dt_iop_module_t *self)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
static int _shape_is_being_added(dt_iop_module_t *self, const int shape_type)
static gboolean _reset_form_creation(GtkWidget *widget, dt_iop_module_t *self)
static __DT_CLONE_TARGETS__ void 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 _edit_masks(GtkWidget *widget, GdkEventButton *e, dt_iop_module_t *self)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
struct dt_iop_spots_params_t dt_iop_spots_data_t
static __DT_CLONE_TARGETS__ int _process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const 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, const int ch)
const char * deprecated_msg()
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)
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)
struct dt_gui_gtk_t * gui
struct dt_develop_t * develop
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
struct dt_iop_module_t * gui_module
struct dt_masks_form_gui_t * form_gui
GtkDarktableToggleButton * off
dt_iop_params_t * default_params
struct dt_develop_blend_params_t * blend_params
struct dt_develop_t * dev
dt_iop_gui_data_t * gui_data
Region of interest passed through the pixelpipe.
GtkWidget * bt_edit_masks