Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
vignette.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010 Alexandre Prokoudine.
4 Copyright (C) 2010-2011 Bruce Guenter.
5 Copyright (C) 2010-2011 Henrik Andersson.
6 Copyright (C) 2010-2013, 2016, 2018 johannes hanika.
7 Copyright (C) 2010 Stuart Henderson.
8 Copyright (C) 2011 Antony Dovgal.
9 Copyright (C) 2011 Jérémy Rosen.
10 Copyright (C) 2011 Olivier Tribout.
11 Copyright (C) 2011 Robert Bieber.
12 Copyright (C) 2011-2014, 2016, 2019 Tobias Ellinghaus.
13 Copyright (C) 2012 José Carlos García Sogo.
14 Copyright (C) 2012 Richard Wonka.
15 Copyright (C) 2012, 2014 Ulrich Pegelow.
16 Copyright (C) 2013, 2018, 2020-2022 Pascal Obry.
17 Copyright (C) 2013 Simon Spannagel.
18 Copyright (C) 2014 Pascal de Bruijn.
19 Copyright (C) 2014-2016, 2019 Roman Lebedev.
20 Copyright (C) 2015 Pedro Côrte-Real.
21 Copyright (C) 2017, 2019 Heiko Bauke.
22 Copyright (C) 2018, 2020, 2022-2023, 2025-2026 Aurélien PIERRE.
23 Copyright (C) 2018 Edgardo Hoszowski.
24 Copyright (C) 2018 Maurizio Paglia.
25 Copyright (C) 2018 rawfiner.
26 Copyright (C) 2019-2020 Aldric Renaudin.
27 Copyright (C) 2019 Andreas Schneider.
28 Copyright (C) 2020, 2022 Chris Elston.
29 Copyright (C) 2020, 2022 Diederik Ter Rahe.
30 Copyright (C) 2020, 2022 Hanno Schwalm.
31 Copyright (C) 2020-2021 Ralf Brown.
32 Copyright (C) 2021 Hubert Kowalski.
33 Copyright (C) 2022 Martin Bařinka.
34 Copyright (C) 2022 Philipp Lutz.
35 Copyright (C) 2025-2026 Guillaume Stutin.
36
37 darktable is free software: you can redistribute it and/or modify
38 it under the terms of the GNU General Public License as published by
39 the Free Software Foundation, either version 3 of the License, or
40 (at your option) any later version.
41
42 darktable is distributed in the hope that it will be useful,
43 but WITHOUT ANY WARRANTY; without even the implied warranty of
44 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 GNU General Public License for more details.
46
47 You should have received a copy of the GNU General Public License
48 along with darktable. If not, see <http://www.gnu.org/licenses/>.
49*/
50#ifdef HAVE_CONFIG_H
51#include "config.h"
52#endif
53#include <assert.h>
54#include "system/macros.h"
55#include "system/openmp.h"
57#include "system/mem_alloc.h"
58#include "common/logging.h"
60#include "database/database.h"
61#include <stdlib.h>
62#include <string.h>
63
64#include "widgets/bauhaus.h"
66#include "math/math.h"
67#include "common/opencl.h"
68#include "pixel/tea.h"
69#include "control/input.h"
70#include "control/control.h"
71#include "develop/develop.h"
72#include "develop/imageop.h"
73#include "develop/imageop_gui.h"
74
75#include "gui/presets.h"
76#include "widgets/draw.h"
77#include "iop/iop_api.h"
78#include <gtk/gtk.h>
79#include <inttypes.h>
80#include "widgets/label.h"
81
83
84typedef enum dt_iop_dither_t
85{
86 DITHER_OFF = 0, // $DESCRIPTION: "off"
87 DITHER_8BIT = 1, // $DESCRIPTION: "8-bit output"
88 DITHER_16BIT = 2 // $DESCRIPTION: "16-bit output"
90
91typedef struct dt_iop_dvector_2d_t
92{
93 double x;
94 double y;
96
97typedef struct dt_iop_fvector_2d_t
98{
99 float x; // $MIN: -1.0 $MAX: 1.0 $DESCRIPTION: "horizontal center"
100 float y; // $MIN: -1.0 $MAX: 1.0 $DESCRIPTION: "vertical center"
102
104{
105 double scale; // 0 - 100 Radie
106 double falloff_scale; // 0 - 100 Radie for falloff inner radie of falloff=scale and
107 // outer=scale+falloff_scale
108 double strength; // 0 - 1 strength of effect
109 double uniformity; // 0 - 1 uniformity of center
110 double bsratio; // -1 - +1 ratio of brightness/saturation effect
113 dt_iop_dvector_2d_t center; // Center of vignette
115
117{
118 float scale; // 0 - 100 Inner radius, percent of largest image dimension
119 float falloff_scale; // 0 - 100 Radius for falloff -- outer radius = inner radius + falloff_scale
120 float brightness; // -1 - 1 Strength of brightness reduction
121 float saturation; // -1 - 1 Strength of saturation reduction
122 dt_iop_vector_2d_t center; // Center of vignette
123 gboolean autoratio; //
124 float whratio; // 0-1 = width/height ratio, 1-2 = height/width ratio + 1
125 float shape;
127
129{
130 float scale; // 0 - 100 Inner radius, percent of largest image dimension
131 float falloff_scale; // 0 - 100 Radius for falloff -- outer radius = inner radius + falloff_scale
132 float brightness; // -1 - 1 Strength of brightness reduction
133 float saturation; // -1 - 1 Strength of saturation reduction
134 dt_iop_vector_2d_t center; // Center of vignette
135 gboolean autoratio; //
136 float whratio; // 0-1 = width/height ratio, 1-2 = height/width ratio + 1
137 float shape;
138 int dithering; // if and how to perform dithering
140
141typedef struct dt_iop_vignette_params_t
142{
143 float scale; // $MIN: 0.0 $MAX: 200.0 $DEFAULT: 80.0 Inner radius, percent of largest image dimension
144 float falloff_scale; // $MIN: 0.0 $MAX: 200.0 $DEFAULT: 50.0 $DESCRIPTION: "fall-off strength" 0 - 100 Radius for falloff -- outer radius = inner radius + falloff_scale
145 float brightness; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: -0.5 -1 - 1 Strength of brightness reduction
146 float saturation; // $MIN: -1.0 $MAX: 1.0 $DEFAULT: -0.5 -1 - 1 Strength of saturation reduction
147 dt_iop_vector_2d_t center; // Center of vignette
148 gboolean autoratio; // $DEFAULT: FALSE $DESCRIPTION: "automatic ratio"
149 float whratio; // $MIN: 0.0 $MAX: 2.0 $DEFAULT: 1.0 $DESCRIPTION: "width vs. height ratio" 0-1 = width/height ratio, 1-2 = height/width ratio + 1
150 float shape; // $MIN: 0.0 $MAX: 5.0 $DEFAULT: 1.0 $DESCRIPTION: "shape"
151 dt_iop_dither_t dithering; // $DEFAULT: DITHER_OFF if and how to perform dithering
152 gboolean unbound; // $DEFAULT: TRUE whether the values should be clipped
154
155
169
183
188
189
190const char *name()
191{
192 return _("_Vignetting");
193}
194
195const char **description(struct dt_iop_module_t *self)
196{
197 return dt_iop_set_description(self, _("simulate a lens fall-off close to edges"),
198 _("creative"),
199 _("non-linear, RGB, display-referred"),
200 _("non-linear, RGB"),
201 _("non-linear, RGB, display-referred"));
202}
203
209
211{
212 return IOP_GROUP_EFFECTS;
213}
214
219
220int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
221 void *new_params, const int new_version)
222{
223 if(old_version == 1 && new_version == 4)
224 {
225 const dt_iop_vignette_params1_t *old = old_params;
226 dt_iop_vignette_params_t *new = new_params;
227 new->scale = old->scale;
228 new->falloff_scale = old->falloff_scale;
229 new->brightness = -(1.0 - MAX(old->bsratio, 0.0)) * old->strength / 100.0;
230 new->saturation = -(1.0 + MIN(old->bsratio, 0.0)) * old->strength / 100.0;
231 if(old->invert_saturation) new->saturation *= -2.0; // Double effect for increasing saturation
232 if(old->invert_falloff) new->brightness = -new->brightness;
233 new->center.x = old->center.x;
234 new->center.y = old->center.y;
235 new->autoratio = TRUE;
236 new->whratio = 1.0;
237 new->shape = 1.0;
238 new->dithering = DITHER_OFF;
239 new->unbound = FALSE;
240 return 0;
241 }
242 if(old_version == 2 && new_version == 4)
243 {
244 const dt_iop_vignette_params2_t *old = old_params;
245 dt_iop_vignette_params_t *new = new_params;
246 new->scale = old->scale;
247 new->falloff_scale = old->falloff_scale;
248 new->brightness = old->brightness;
249 new->saturation = old->saturation;
250 new->center.x = old->center.x;
251 new->center.y = old->center.y;
252 new->autoratio = old->autoratio;
253 new->whratio = old->whratio;
254 new->shape = old->shape;
255 new->dithering = DITHER_OFF;
256 new->unbound = FALSE;
257 return 0;
258 }
259 if(old_version == 3 && new_version == 4)
260 {
261 const dt_iop_vignette_params3_t *old = old_params;
262 dt_iop_vignette_params_t *new = new_params;
263 new->scale = old->scale;
264 new->falloff_scale = old->falloff_scale;
265 new->brightness = old->brightness;
266 new->saturation = old->saturation;
267 new->center.x = old->center.x;
268 new->center.y = old->center.y;
269 new->autoratio = old->autoratio;
270 new->whratio = old->whratio;
271 new->shape = old->shape;
272 new->dithering = old->dithering;
273 new->unbound = FALSE;
274 return 0;
275 }
276
277 return 1;
278}
279
280/* The vignette is computed on the module's own input frame (piece->buf_in, see process()),
281 * which sits upstream of lens, crop, flip, ashift... Its geometry is therefore stated in that
282 * frame, at full resolution, and only projected through the downstream distortions to be
283 * drawn or hit-tested. */
285{
286 float width; // module input frame, full resolution
287 float height;
288 float longest; // MAX(width, height), the basis of a fixed w/h ratio
289 float cx; // vignette center
290 float cy;
291 float rx; // inner radii: start of the falloff
292 float ry;
293 float frx; // outer radii: end of the falloff
294 float fry;
295 float shape;
297
298#define VIGNETTE_OUTLINE_SAMPLES 128
299
302{
303 dt_iop_roi_t in;
304 if(!dt_dev_module_geometry_gui(self->dev, self, &in, NULL)) return FALSE;
305 if(in.width <= 0 || in.height <= 0) return FALSE;
306
307 geo->width = in.width;
308 geo->height = in.height;
309 geo->longest = MAX(geo->width, geo->height);
310 geo->cx = (p->center.x + 1.0f) * 0.5f * geo->width;
311 geo->cy = (p->center.y + 1.0f) * 0.5f * geo->height;
312
313 // Half-axes of the unit ellipse, mirroring xscale/yscale in process()
314 float half_x;
315 float half_y;
316 if(p->autoratio)
317 {
318 half_x = 0.5f * geo->width;
319 half_y = 0.5f * geo->height;
320 }
321 else if(p->whratio <= 1.0f)
322 {
323 half_x = 0.5f * geo->longest * p->whratio;
324 half_y = 0.5f * geo->longest;
325 }
326 else
327 {
328 half_x = 0.5f * geo->longest;
329 half_y = 0.5f * geo->longest * (2.0f - p->whratio);
330 }
331
332 const float dscale = p->scale / 100.0f;
333 const float min_falloff = 100.0f / MIN(geo->width, geo->height);
334 const float fscale = MAX(p->falloff_scale, min_falloff) / 100.0f;
335 geo->rx = dscale * half_x;
336 geo->ry = dscale * half_y;
337 geo->frx = (dscale + fscale) * half_x;
338 geo->fry = (dscale + fscale) * half_y;
339 geo->shape = MAX(p->shape, 0.001f);
340 return TRUE;
341}
342
343/* Module frame (full resolution) -> developed image, absolute pixels. */
344static gboolean _module_to_image_abs(dt_iop_module_t *self, float *pts, const size_t count)
345{
346 return dt_dev_distort_transform_gui(self->dev, self->iop_order, DT_DEV_TRANSFORM_DIR_FORW_EXCL, pts, count) != 0;
347}
348
349/* Widget pointer -> module frame (full resolution). */
350static gboolean _widget_to_module(dt_iop_module_t *self, const double x, const double y, float pt[2])
351{
352 pt[0] = (float)x;
353 pt[1] = (float)y;
357}
358
359/* The five handles in module frame: center, inner x, inner y, outer x, outer y.
360 * Their order is the grab identifiers' bit order below. */
361static void _vignette_handles(const dt_iop_vignette_geometry_t *geo, float pts[10])
362{
363 pts[0] = geo->cx; pts[1] = geo->cy;
364 pts[2] = geo->cx + geo->rx; pts[3] = geo->cy;
365 pts[4] = geo->cx; pts[5] = geo->cy - geo->ry;
366 pts[6] = geo->cx + geo->frx; pts[7] = geo->cy;
367 pts[8] = geo->cx; pts[9] = geo->cy - geo->fry;
368}
369
370/* Hit test in developed-image pixels, where DT_GUI_MOUSE_EFFECT_RADIUS is expressed.
371 * Returns 1 center, 2 x size, 4 y size, 8 x falloff, 16 y falloff, 0 nothing. */
372static int _get_grab(dt_iop_module_t *self, const dt_iop_vignette_geometry_t *geo, const double x,
373 const double y)
374{
375 float handles[10];
376 _vignette_handles(geo, handles);
377 if(!_module_to_image_abs(self, handles, 5)) return 0;
378
379 float pointer[2] = { (float)x, (float)y };
382
383 const float radius = DT_GUI_MOUSE_EFFECT_RADIUS;
384 const float radius_sq = radius * radius;
385 // Size handles first, so they stay reachable on a vignette shrunk onto its center
386 static const int order[5] = { 1, 2, 0, 3, 4 };
387 for(int k = 0; k < 5; k++)
388 {
389 const int i = order[k];
390 const float dx = pointer[0] - handles[2 * i];
391 const float dy = pointer[1] - handles[2 * i + 1];
392 if(dx * dx + dy * dy <= radius_sq) return 1 << i;
393 }
394 return 0;
395}
396
397/* Superellipse |x/rx|^(2/shape) + |y/ry|^(2/shape) = 1, the iso-line process() thresholds on. */
398static void _outline_sample(const dt_iop_vignette_geometry_t *geo, const float rx, const float ry,
399 float *pts)
400{
401 for(int i = 0; i < VIGNETTE_OUTLINE_SAMPLES; i++)
402 {
403 const float t = 2.0f * M_PI * i / VIGNETTE_OUTLINE_SAMPLES;
404 const float c = cosf(t);
405 const float s = sinf(t);
406 pts[2 * i] = geo->cx + rx * copysignf(powf(fabsf(c), geo->shape), c);
407 pts[2 * i + 1] = geo->cy + ry * copysignf(powf(fabsf(s), geo->shape), s);
408 }
409}
410
411static void _draw_closed_path(cairo_t *cr, const float *pts, const int count)
412{
413 cairo_move_to(cr, pts[0], pts[1]);
414 for(int i = 1; i < count; i++) cairo_line_to(cr, pts[2 * i], pts[2 * i + 1]);
415 cairo_close_path(cr);
416 cairo_stroke(cr);
417}
418
419static void _draw_overlay(cairo_t *cr, const float *inner, const float *outer, const float *handles,
420 const int grab, const float zoom_scale)
421{
422 // half width/height of the crosshair
423 const float crosshair = DT_PIXEL_APPLY_DPI(10.0) / zoom_scale;
424 cairo_move_to(cr, handles[0] - crosshair, handles[1]);
425 cairo_line_to(cr, handles[0] + crosshair, handles[1]);
426 cairo_move_to(cr, handles[0], handles[1] - crosshair);
427 cairo_line_to(cr, handles[0], handles[1] + crosshair);
428 cairo_stroke(cr);
429
432
433 const float radius_sel = DT_PIXEL_APPLY_DPI(6.0) / zoom_scale;
434 const float radius_reg = DT_PIXEL_APPLY_DPI(4.0) / zoom_scale;
435 for(int i = 0; i < 5; i++)
436 {
437 cairo_new_sub_path(cr);
438 cairo_arc(cr, handles[2 * i], handles[2 * i + 1], (grab == (1 << i)) ? radius_sel : radius_reg, 0.0,
439 M_PI * 2.0);
440 cairo_stroke(cr);
441 }
442}
443
444void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height,
445 int32_t pointerx, int32_t pointery)
446{
447 dt_develop_t *dev = self->dev;
450 if(IS_NULL_PTR(g) || IS_NULL_PTR(p)) return;
451
453 if(!_vignette_geometry(self, p, &geo)) return;
454
455 // Everything is sampled in the module frame and carried to the preview through the
456 // downstream distortions in one batch: inner outline, outer outline, handles.
457 const size_t count = 2 * VIGNETTE_OUTLINE_SAMPLES + 5;
458 float pts[2 * (2 * VIGNETTE_OUTLINE_SAMPLES + 5)];
459 float *inner = pts;
460 float *outer = pts + 2 * VIGNETTE_OUTLINE_SAMPLES;
461 float *handles = pts + 4 * VIGNETTE_OUTLINE_SAMPLES;
462 _outline_sample(&geo, geo.rx, geo.ry, inner);
463 _outline_sample(&geo, geo.frx, geo.fry, outer);
464 _vignette_handles(&geo, handles);
465 if(!_module_to_image_abs(self, pts, count)) return;
468
469 const int grab = _get_grab(self, &geo, pointerx, pointery);
470 const float zoom_scale = dt_dev_get_overlay_scale(dev);
472
473 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
474 cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
475 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(3.0) / zoom_scale);
477 _draw_overlay(cr, inner, outer, handles, grab, zoom_scale);
478 cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0) / zoom_scale);
480 _draw_overlay(cr, inner, outer, handles, grab, zoom_scale);
481}
482
483// FIXME: Pumping of the opposite direction when changing width/height. See two FIXMEs further down.
484int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
485{
488 if(IS_NULL_PTR(g) || IS_NULL_PTR(p)) return 0;
489
491 if(!_vignette_geometry(self, p, &geo)) return 0;
492 const float longest = geo.longest;
493
494 static int old_grab = -1;
495 int grab = old_grab;
496
497 if(grab == 0 || !(dt_control_button_down(1)))
498 grab = _get_grab(self, &geo, x, y);
499
501 {
502 if(grab == 0) // pan the image
503 {
504 dt_control_queue_cursor(GDK_HAND1);
505 return 0;
506 }
507
508 float pointer[2];
509 if(!_widget_to_module(self, x, y, pointer)) return 1;
510 const float mx = pointer[0];
511 const float my = pointer[1];
512
513 if(grab == 1) // move the center
514 {
515 dt_bauhaus_slider_set(g->center_x, mx / geo.width * 2.0f - 1.0f);
516 dt_bauhaus_slider_set(g->center_y, my / geo.height * 2.0f - 1.0f);
517 }
518 else if(grab == 2) // change the width
519 {
520 const float max = 0.5f * ((p->whratio <= 1.0f) ? longest * p->whratio : longest);
521 const float new_vignette_w = MIN(longest, MAX(0.1f, mx - geo.cx));
522 const float ratio = new_vignette_w / geo.ry;
523 const float new_scale = 100.0f * new_vignette_w / max;
524 // FIXME: When going over the 1.0 boundary from wide to narrow (>1.0 -> <=1.0) the height slightly
525 // changes, depending on speed.
526 // I guess we have to split the computation.
527 if(ratio <= 1.0f)
528 {
530 dt_bauhaus_slider_set(g->scale, new_scale);
531 else
532 dt_bauhaus_slider_set(g->whratio, ratio);
533 }
534 else
535 {
536 dt_bauhaus_slider_set(g->scale, new_scale);
538 dt_bauhaus_slider_set(g->whratio, 2.0f - 1.0f / ratio);
539 }
540 }
541 else if(grab == 4) // change the height
542 {
543 const float new_vignette_h = MIN(longest, MAX(0.1f, geo.cy - my));
544 const float ratio = new_vignette_h / geo.rx;
545 const float max = 0.5f * ((ratio <= 1.0f) ? longest * (2.0f - p->whratio) : longest);
546 // FIXME: When going over the 1.0 boundary from narrow to wide (>1.0 -> <=1.0) the width slightly
547 // changes, depending on speed.
548 // I guess we have to split the computation.
549 if(ratio <= 1.0f)
550 {
552 dt_bauhaus_slider_set(g->scale, 100.0f * new_vignette_h / max);
553 else
554 dt_bauhaus_slider_set(g->whratio, 2.0f - ratio);
555 }
556 else
557 {
558 dt_bauhaus_slider_set(g->scale, 100.0f * new_vignette_h / max);
560 dt_bauhaus_slider_set(g->whratio, 1.0f / ratio);
561 }
562 }
563 else if(grab == 8) // change the falloff on the right
564 {
565 const float max = 0.5f * ((p->whratio <= 1.0f) ? longest * p->whratio : longest);
566 const float delta_x = MIN(2.0f * max, MAX(0.0f, mx - geo.cx - geo.rx));
567 dt_bauhaus_slider_set(g->falloff_scale, 100.0f * delta_x / max);
568 }
569 else if(grab == 16) // change the falloff on the top
570 {
571 const float max = 0.5f * ((p->whratio > 1.0f) ? longest * (2.0f - p->whratio) : longest);
572 const float delta_y = MIN(2.0f * max, MAX(0.0f, geo.cy - my - geo.ry));
573 dt_bauhaus_slider_set(g->falloff_scale, 100.0f * delta_y / max);
574 }
576 return 1;
577 }
578 else if(grab)
579 {
580 if(grab == 1)
581 dt_control_queue_cursor(GDK_FLEUR);
582 else if(grab == 2 || grab == 8)
583 dt_control_queue_cursor(GDK_SB_H_DOUBLE_ARROW);
584 else if(grab == 4 || grab == 16)
585 dt_control_queue_cursor(GDK_SB_V_DOUBLE_ARROW);
586 }
587 else
588 {
589 if(old_grab != grab) dt_control_queue_cursor(GDK_LEFT_PTR);
590 }
591 old_grab = grab;
593 return 0;
594}
595
596int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type,
597 uint32_t state)
598{
599 if(which == 1) return 1;
600 return 0;
601}
602
603int button_released(struct dt_iop_module_t *self, double x, double y, int which, uint32_t state)
604{
605 if(which == 1) return 1;
606 return 0;
607}
608
610int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
611 void *const ovoid)
612{
613 const dt_iop_roi_t *const roi_in = &piece->roi_in;
614 const dt_iop_roi_t *const roi_out = &piece->roi_out;
616 const dt_iop_roi_t *buf_in = &piece->buf_in;
617 const size_t ch = piece->dsc_in.channels;
618 const gboolean unbound = data->unbound;
619
620 /* Center coordinates of buf_in, these should not consider buf_in->{x,y}! */
621 const dt_iop_vector_2d_t buf_center = { buf_in->width * .5f, buf_in->height * .5f };
622 /* Center coordinates of vignette center */
623 const dt_iop_vector_2d_t vignette_center = { buf_center.x + data->center.x * buf_in->width / 2.0,
624 buf_center.y + data->center.y * buf_in->height / 2.0 };
625 /* Coordinates of vignette_center in terms of roi_in */
626 const dt_iop_vector_2d_t roi_center
627 = { vignette_center.x * roi_in->scale - roi_in->x, vignette_center.y * roi_in->scale - roi_in->y };
628 float xscale;
629 float yscale;
630
631 /* w/h ratio follows piece dimensions */
632 if(data->autoratio)
633 {
634 xscale = 2.0 / (buf_in->width * roi_out->scale);
635 yscale = 2.0 / (buf_in->height * roi_out->scale);
636 }
637 else /* specified w/h ratio, scale proportional to longest side */
638 {
639 const float basis = 2.0 / (MAX(buf_in->height, buf_in->width) * roi_out->scale);
640 // w/h ratio from 0-1 use as-is
641 if(data->whratio <= 1.0)
642 {
643 yscale = basis;
644 xscale = yscale / data->whratio;
645 }
646 // w/h ratio from 1-2 interpret as 1-inf
647 // that is, the h/w ratio + 1
648 else
649 {
650 xscale = basis;
651 yscale = xscale / (2.0 - data->whratio);
652 }
653 }
654 const float dscale = data->scale / 100.0;
655 // A minimum falloff is used, based on the image size, to smooth out aliasing artifacts
656 const float min_falloff = 100.0 / MIN(buf_in->width, buf_in->height);
657 const float fscale = MAX(data->falloff_scale, min_falloff) / 100.0;
658 const float shape = MAX(data->shape, 0.001);
659 const float exp1 = 2.0 / shape;
660 const float exp2 = shape / 2.0;
661 // Pre-scale the center offset
662 const dt_iop_vector_2d_t roi_center_scaled = { roi_center.x * xscale, roi_center.y * yscale };
663
664 float dither = 0.0f;
665
666 switch(data->dithering)
667 {
668 case DITHER_8BIT:
669 dither = 1.0f / 256;
670 break;
671 case DITHER_16BIT:
672 dither = 1.0f / 65536;
673 break;
674 case DITHER_OFF:
675 default:
676 dither = 0.0f;
677 }
678
679 unsigned int *const tea_states = alloc_tea_states(dt_get_num_openmp_threads());
681 for(int j = 0; j < roi_out->height; j++)
682 {
683 const size_t k = (size_t)ch * roi_out->width * j;
684 const float *in = (const float *)ivoid + k;
685 float *out = (float *)ovoid + k;
686 unsigned int *tea_state = get_tea_state(tea_states,dt_get_thread_num());
687 tea_state[0] = j * roi_out->height; /* + dt_get_thread_num() -- do not include, makes results unreproducible */
688 for(int i = 0; i < roi_out->width; i++, in += ch, out += ch)
689 {
690 // current pixel coord translated to local coord
691 const dt_iop_vector_2d_t pv
692 = { fabsf(i * xscale - roi_center_scaled.x), fabsf(j * yscale - roi_center_scaled.y) };
693
694 // Calculate the pixel weight in vignette
695 const float cplen = powf(powf(pv.x, exp1) + powf(pv.y, exp1), exp2); // Length from center to pv
696 float weight = 0.0;
697 float dith = 0.0;
698
699 if(cplen >= dscale) // pixel is outside the inner vignette circle, lets calculate weight of vignette
700 {
701 weight = ((cplen - dscale) / fscale);
702 if(weight >= 1.0)
703 weight = 1.0;
704 else if(weight <= 0.0)
705 weight = 0.0;
706 else if(dither == 0.0f)
707 {
708 // don't bother computing the random number if dithering is disabled
709 dith = 0.0f;
710 }
711 else
712 {
713 weight = 0.5 - cosf(M_PI * weight) / 2.0;
714 encrypt_tea(tea_state);
715 dith = dither * tpdf(tea_state[0]);
716 }
717 }
718
719 // Let's apply weighted effect on brightness and desaturation
720 float col0 = in[0], col1 = in[1], col2 = in[2], col3 = in[3];
721 if(weight > 0)
722 {
723 // Then apply falloff vignette
724 float falloff = (data->brightness < 0) ? (1.0f + (weight * data->brightness))
725 : (weight * data->brightness);
726 col0 = data->brightness < 0 ? col0 * falloff + dith : col0 + falloff + dith;
727 col1 = data->brightness < 0 ? col1 * falloff + dith : col1 + falloff + dith;
728 col2 = data->brightness < 0 ? col2 * falloff + dith : col2 + falloff + dith;
729
730 col0 = unbound ? col0 : CLIP(col0);
731 col1 = unbound ? col1 : CLIP(col1);
732 col2 = unbound ? col2 : CLIP(col2);
733
734 // apply saturation
735 float mv = (col0 + col1 + col2) / 3.0f;
736 float wss = weight * data->saturation;
737 col0 = col0 - ((mv - col0) * wss);
738 col1 = col1 - ((mv - col1) * wss);
739 col2 = col2 - ((mv - col2) * wss);
740
741 col0 = unbound ? col0 : CLIP(col0);
742 col1 = unbound ? col1 : CLIP(col1);
743 col2 = unbound ? col2 : CLIP(col2);
744 }
745
746 out[0] = col0;
747 out[1] = col1;
748 out[2] = col2;
749 out[3] = col3;
750 }
751 }
752
753 free_tea_states(tea_states);
754 return 0;
755}
756
757
758#ifdef HAVE_OPENCL
759int 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)
760{
761 const dt_iop_roi_t *const roi_in = &piece->roi_in;
762 const dt_iop_roi_t *const roi_out = &piece->roi_out;
765
766 cl_int err = -999;
767 const int devid = pipe->devid;
768 const int width = roi_out->width;
769 const int height = roi_out->height;
770
771 const dt_iop_roi_t *buf_in = &piece->buf_in;
772
773 /* Center coordinates of buf_in, these should not consider buf_in->{x,y}! */
774 const dt_iop_vector_2d_t buf_center = { buf_in->width * .5f, buf_in->height * .5f };
775 /* Center coordinates of vignette center */
776 const dt_iop_vector_2d_t vignette_center = { buf_center.x + data->center.x * buf_in->width / 2.0,
777 buf_center.y + data->center.y * buf_in->height / 2.0 };
778 /* Coordinates of vignette_center in terms of roi_in */
779 const dt_iop_vector_2d_t roi_center
780 = { vignette_center.x * roi_in->scale - roi_in->x, vignette_center.y * roi_in->scale - roi_in->y };
781 float xscale;
782 float yscale;
783
784 /* w/h ratio follows piece dimensions */
785 if(data->autoratio)
786 {
787 xscale = 2.0 / (buf_in->width * roi_out->scale);
788 yscale = 2.0 / (buf_in->height * roi_out->scale);
789 }
790 else /* specified w/h ratio, scale proportional to longest side */
791 {
792 const float basis = 2.0 / (MAX(buf_in->height, buf_in->width) * roi_out->scale);
793 // w/h ratio from 0-1 use as-is
794 if(data->whratio <= 1.0)
795 {
796 yscale = basis;
797 xscale = yscale / data->whratio;
798 }
799 // w/h ratio from 1-2 interpret as 1-inf
800 // that is, the h/w ratio + 1
801 else
802 {
803 xscale = basis;
804 yscale = xscale / (2.0 - data->whratio);
805 }
806 }
807 const float dscale = data->scale / 100.0;
808 // A minimum falloff is used, based on the image size, to smooth out aliasing artifacts
809 const float min_falloff = 100.0 / MIN(buf_in->width, buf_in->height);
810 const float fscale = MAX(data->falloff_scale, min_falloff) / 100.0;
811 const float shape = MAX(data->shape, 0.001);
812 const float exp1 = 2.0 / shape;
813 const float exp2 = shape / 2.0;
814 // Pre-scale the center offset
815 const dt_iop_vector_2d_t roi_center_scaled = { roi_center.x * xscale, roi_center.y * yscale };
816
817 float dither = 0.0f;
818
819 switch(data->dithering)
820 {
821 case DITHER_8BIT:
822 dither = 1.0f / 256;
823 break;
824 case DITHER_16BIT:
825 dither = 1.0f / 65536;
826 break;
827 case DITHER_OFF:
828 default:
829 dither = 0.0f;
830 }
831
832 float scale[2] = { xscale, yscale };
833 float roi_center_scaled_f[2] = { roi_center_scaled.x, roi_center_scaled.y };
834 float expt[2] = { exp1, exp2 };
835 const float brightness = data->brightness;
836 const float saturation = data->saturation;
837 const int unbound = data->unbound;
838
839 size_t sizes[2] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid) };
840
841 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 0, sizeof(cl_mem), &dev_in);
842 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 1, sizeof(cl_mem), &dev_out);
843 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 2, sizeof(int), &width);
844 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 3, sizeof(int), &height);
845 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 4, 2 * sizeof(float), &scale);
846 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 5, 2 * sizeof(float), &roi_center_scaled_f);
847 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 6, 2 * sizeof(float), &expt);
848 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 7, sizeof(float), &dscale);
849 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 8, sizeof(float), &fscale);
850 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 9, sizeof(float), &brightness);
851 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 10, sizeof(float), &saturation);
852 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 11, sizeof(float), &dither);
853 dt_opencl_set_kernel_arg(devid, gd->kernel_vignette, 12, sizeof(int), &unbound);
854 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_vignette, sizes);
855 if(err != CL_SUCCESS) goto error;
856
857 return TRUE;
858
859error:
860 dt_print(DT_DEBUG_OPENCL, "[opencl_vignette] couldn't enqueue kernel! %d\n", err);
861 return FALSE;
862}
863#endif
864
865
867{
868 const int program = 8; // extended.cl from programs.conf
871 module->data = gd;
872 gd->kernel_vignette = dt_opencl_create_kernel(program, "vignette");
873}
874
875
882
883
884void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
885{
888 if(IS_NULL_PTR(g) || IS_NULL_PTR(p)) return;
889
890 gtk_widget_set_sensitive(GTK_WIDGET(g->whratio), !p->autoratio);
891}
892
895{
898 d->scale = p->scale;
899 d->falloff_scale = p->falloff_scale;
900 d->brightness = p->brightness;
901 d->saturation = p->saturation;
902 d->center = p->center;
903 d->autoratio = p->autoratio;
904 d->whratio = p->whratio;
905 d->shape = p->shape;
906 d->dithering = p->dithering;
907 d->unbound = p->unbound;
908}
909
911{
914 p.scale = 40.0f;
915 p.falloff_scale = 100.0f;
916 p.brightness = -1.0f;
917 p.saturation = 0.5f;
918 p.center.x = 0.0f;
919 p.center.y = 0.0f;
920 p.autoratio = FALSE;
921 p.whratio = 1.0f;
922 p.shape = 1.0f;
923 p.dithering = 0;
924 p.unbound = TRUE;
925 dt_gui_presets_add_generic(_("lomo"), self->op,
926 self->version(), &p, sizeof(p), 1);
928}
929
935
937{
938 dt_free_align(piece->data);
939 piece->data = NULL;
940}
941
942void gui_update(struct dt_iop_module_t *self)
943{
946 if(IS_NULL_PTR(g) || IS_NULL_PTR(p)) return;
947 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->autoratio), p->autoratio);
948 gtk_widget_set_sensitive(GTK_WIDGET(g->whratio), !p->autoratio);
949}
950
951void gui_init(struct dt_iop_module_t *self)
952{
954
955 g->scale = dt_bauhaus_slider_from_params(self, N_("scale"));
956 g->falloff_scale = dt_bauhaus_slider_from_params(self, "falloff_scale");
957 g->brightness = dt_bauhaus_slider_from_params(self, N_("brightness"));
958 g->saturation = dt_bauhaus_slider_from_params(self, N_("saturation"));
959
960 gtk_box_pack_start(GTK_BOX(self->gui->widget),
961 dt_ui_section_label_new(_("position / form")), FALSE, FALSE, 0);
962
963 g->center_x = dt_bauhaus_slider_from_params(self, "center.x");
964 g->center_y = dt_bauhaus_slider_from_params(self, "center.y");
965 g->shape = dt_bauhaus_slider_from_params(self, N_("shape"));
966 g->autoratio = dt_bauhaus_toggle_from_params(self, "autoratio");
967 g->whratio = dt_bauhaus_slider_from_params(self, "whratio");
968 g->dithering = dt_bauhaus_combobox_from_params(self, N_("dithering"));
969
970 dt_bauhaus_slider_set_digits(g->brightness, 3);
971 dt_bauhaus_slider_set_digits(g->saturation, 3);
972 dt_bauhaus_slider_set_digits(g->center_x, 3);
973 dt_bauhaus_slider_set_digits(g->center_y, 3);
974 dt_bauhaus_slider_set_digits(g->whratio, 3);
975
976 dt_bauhaus_slider_set_format(g->scale, "%");
977 dt_bauhaus_slider_set_format(g->falloff_scale, "%");
978
979 gtk_widget_set_tooltip_text(g->scale, _("the radii scale of vignette for start of fall-off"));
980 gtk_widget_set_tooltip_text(g->falloff_scale, _("the radii scale of vignette for end of fall-off"));
981 gtk_widget_set_tooltip_text(g->brightness, _("strength of effect on brightness"));
982 gtk_widget_set_tooltip_text(g->saturation, _("strength of effect on saturation"));
983 gtk_widget_set_tooltip_text(g->center_x, _("horizontal offset of center of the effect"));
984 gtk_widget_set_tooltip_text(g->center_y, _("vertical offset of center of the effect"));
985 gtk_widget_set_tooltip_text(g->shape, _("shape factor\n0 produces a rectangle\n1 produces a circle or ellipse\n"
986 "2 produces a diamond"));
987 gtk_widget_set_tooltip_text(GTK_WIDGET(g->autoratio), _("enable to have the ratio automatically follow the image size"));
988 gtk_widget_set_tooltip_text(g->whratio, _("width-to-height ratio"));
989 gtk_widget_set_tooltip_text(g->dithering, _("add some level of random noise to prevent banding"));
990}
991
992// clang-format off
993// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
994// vim: shiftwidth=2 expandtab tabstop=2 cindent
995// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
996// clang-format on
Handle default and user-set shortcuts (accelerators)
#define DT_PRIMARY_MASK
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
Definition bauhaus.c:3346
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3334
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3410
@ IOP_CS_RGB
static const float x
const int t
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const float max
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
Definition control.c:970
gboolean dt_control_button_down(int which)
Is mouse button which currently held down?
Definition control.c:578
#define dt_control_queue_cursor(cursor)
Definition control.h:140
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
Definition darktable.c:521
#define dt_database_start_transaction()
Definition database.h:290
#define dt_database_release_transaction()
Definition database.h:291
void dt_iop_params_t
Definition dev_history.h:43
void dt_dev_coordinates_image_abs_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1286
int dt_dev_distort_backtransform_gui(dt_develop_t *dev, const double iop_order, const int transf_direction, float *points, size_t points_count)
The inverse of dt_dev_distort_transform_gui(), same rules.
Definition develop.c:1766
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
Definition develop.c:2026
void dt_dev_coordinates_image_norm_to_preview_abs(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1358
gboolean dt_dev_module_geometry_gui(dt_develop_t *dev, dt_iop_module_t *module, dt_iop_roi_t *in, dt_iop_roi_t *out)
One module's own input and output rectangles at full resolution, from the geometry service.
Definition develop.c:1818
int dt_dev_distort_transform_gui(dt_develop_t *dev, const double iop_order, const int transf_direction, float *points, size_t points_count)
The GUI's bounded transform folds, composed by the geometry service.
Definition develop.c:1758
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.
Definition develop.c:2138
void dt_dev_coordinates_image_norm_to_image_abs(dt_develop_t *dev, float *points, size_t num_points)
Definition develop.c:1270
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.
Definition develop.c:1211
@ DT_DEV_TRANSFORM_DIR_FORW_EXCL
Definition develop.h:109
static void dt_draw_set_color_overlay(cairo_t *cr, gboolean bright, double alpha)
Definition draw.h:147
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
Definition eaw.c:29
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 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)
Definition imageop.c:1909
@ IOP_FLAGS_INCLUDE_IN_STYLES
Definition imageop.h:185
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:188
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:190
@ IOP_GROUP_EFFECTS
Definition imageop.h:161
GtkWidget * dt_bauhaus_toggle_from_params(dt_iop_module_t *self, const char *param)
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...
Definition imageop_gui.h:81
#define IOP_GUI_ALLOC(module)
Definition imageop_gui.h:93
void *const ovoid
Which mouse buttons are held, asked of the toolkit rather than remembered.
GtkWidget * dt_ui_section_label_new(const gchar *str)
Definition label.c:114
static const dt_dev_pixelpipe_t * pipe
Definition layers.h:49
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t * piece
Definition layers.h:50
dt_iop_dither_t
Definition lightroom.c:110
_lib_location_type_t type
Definition location.c:1
@ DT_DEBUG_OPENCL
Definition logging.h:57
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 k
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...
Definition macros.h:96
#define CLIP(x)
Definition math.h:83
#define M_PI
Definition math.h:47
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
Definition mem_alloc.h:225
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#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)
Definition opencl.c:2612
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2506
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2549
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2603
#define ROUNDUPDHT(a, b)
Definition opencl.h:86
#define ROUNDUPDWD(a, b)
Definition opencl.h:85
static int dt_get_thread_num()
Index of the calling thread within its parallel region, 0 outside one.
Definition openmp.h:129
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
const float uint32_t state[4]
GtkWidget * widget
Definition imageop_gui.h:47
dt_dev_operation_t op
Definition imageop.h:235
dt_iop_global_data_t * data
Definition imageop.h:238
struct dt_iop_module_gui_t * gui
Definition imageop.h:346
struct dt_develop_t * dev
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:337
dt_iop_params_t * params
Definition imageop.h:333
Region of interest passed through the pixelpipe.
Definition format.h:49
double scale
Definition format.h:51
int width
Definition format.h:50
int height
Definition format.h:50
dt_iop_vector_2d_t center
Definition vignette.c:176
dt_iop_dvector_2d_t center
Definition vignette.c:113
dt_iop_vector_2d_t center
Definition vignette.c:122
dt_iop_vector_2d_t center
Definition vignette.c:134
dt_iop_dither_t dithering
Definition vignette.c:151
dt_iop_vector_2d_t center
Definition lightroom.c:129
#define __DT_CLONE_TARGETS__
static float tpdf(unsigned int urandom)
Definition tea.h:74
static unsigned int * get_tea_state(unsigned int *const states, int threadnum)
Definition tea.h:43
static void free_tea_states(unsigned int *states)
Definition tea.h:48
static unsigned int * alloc_tea_states(size_t numthreads)
Definition tea.h:34
static void encrypt_tea(unsigned int *arg)
Definition tea.h:58
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
static void _vignette_handles(const dt_iop_vignette_geometry_t *geo, float pts[10])
Definition vignette.c:361
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)
Definition vignette.c:893
const char ** description(struct dt_iop_module_t *self)
Definition vignette.c:195
int default_group()
Definition vignette.c:210
__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 void *const ivoid, void *const ovoid)
Definition vignette.c:610
static gboolean _widget_to_module(dt_iop_module_t *self, const double x, const double y, float pt[2])
Definition vignette.c:350
dt_iop_dither_t
Definition vignette.c:85
@ DITHER_16BIT
Definition vignette.c:88
@ DITHER_8BIT
Definition vignette.c:87
@ DITHER_OFF
Definition vignette.c:86
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition vignette.c:930
static void _outline_sample(const dt_iop_vignette_geometry_t *geo, const float rx, const float ry, float *pts)
Definition vignette.c:398
const char * name()
Definition vignette.c:190
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
Definition vignette.c:942
static gboolean _vignette_geometry(dt_iop_module_t *self, const dt_iop_vignette_params_t *p, dt_iop_vignette_geometry_t *geo)
Definition vignette.c:300
void gui_init(struct dt_iop_module_t *self)
Definition vignette.c:951
int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
Definition vignette.c:596
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition vignette.c:884
int button_released(struct dt_iop_module_t *self, double x, double y, int which, uint32_t state)
Definition vignette.c:603
#define VIGNETTE_OUTLINE_SAMPLES
Definition vignette.c:298
void cleanup_global(dt_iop_module_so_t *module)
Definition vignette.c:876
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition vignette.c:215
int flags()
Definition vignette.c:204
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)
Definition vignette.c:444
static void _draw_overlay(cairo_t *cr, const float *inner, const float *outer, const float *handles, const int grab, const float zoom_scale)
Definition vignette.c:419
void init_presets(dt_iop_module_so_t *self)
Definition vignette.c:910
struct dt_iop_fvector_2d_t dt_iop_vector_2d_t
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition vignette.c:936
void init_global(dt_iop_module_so_t *module)
Definition vignette.c:866
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)
Definition vignette.c:759
int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
Definition vignette.c:484
static gboolean _module_to_image_abs(dt_iop_module_t *self, float *pts, const size_t count)
Definition vignette.c:344
static int _get_grab(dt_iop_module_t *self, const dt_iop_vignette_geometry_t *geo, const double x, const double y)
Definition vignette.c:372
static void _draw_closed_path(cairo_t *cr, const float *pts, const int count)
Definition vignette.c:411
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
Definition vignette.c:220
static gboolean dt_modifier_is(GdkModifierType state, const GdkModifierType desired_modifier_mask)
#define DT_GUI_MOUSE_EFFECT_RADIUS
#define DT_PIXEL_APPLY_DPI(value)