Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
borders.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011 Brian Teague.
4 Copyright (C) 2011-2012 Henrik Andersson.
5 Copyright (C) 2011-2013, 2016 johannes hanika.
6 Copyright (C) 2011 Olivier Tribout.
7 Copyright (C) 2011, 2013 Pascal de Bruijn.
8 Copyright (C) 2011 Robert Bieber.
9 Copyright (C) 2011 Rostyslav Pidgornyi.
10 Copyright (C) 2011-2014, 2016, 2018-2019 Tobias Ellinghaus.
11 Copyright (C) 2012 Loic Guibert.
12 Copyright (C) 2012 parafin.
13 Copyright (C) 2012 Richard Levitte.
14 Copyright (C) 2012 Richard Wonka.
15 Copyright (C) 2012-2016 Ulrich Pegelow.
16 Copyright (C) 2013, 2020-2021 Aldric Renaudin.
17 Copyright (C) 2013 Dennis Gnad.
18 Copyright (C) 2013, 2017-2022 Pascal Obry.
19 Copyright (C) 2013-2016 Roman Lebedev.
20 Copyright (C) 2015 Pedro Côrte-Real.
21 Copyright (C) 2018-2021, 2023-2026 Aurélien PIERRE.
22 Copyright (C) 2018-2019 Edgardo Hoszowski.
23 Copyright (C) 2018 Maurizio Paglia.
24 Copyright (C) 2018 rawfiner.
25 Copyright (C) 2019 Barna Keresztes.
26 Copyright (C) 2019-2022 Diederik Ter Rahe.
27 Copyright (C) 2019 Diederik ter Rahe.
28 Copyright (C) 2019 Jacques Le Clerc.
29 Copyright (C) 2020 Chris Elston.
30 Copyright (C) 2020 Hubert Kowalski.
31 Copyright (C) 2020-2021 Ralf Brown.
32 Copyright (C) 2021 luzpaz.
33 Copyright (C) 2022 Hanno Schwalm.
34 Copyright (C) 2022 Martin Bařinka.
35 Copyright (C) 2022 Philipp Lutz.
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 "common/darktable.h"
52#include "config.h"
53#endif
54#include "bauhaus/bauhaus.h"
55#include "common/debug.h"
56#include "common/imagebuf.h"
57#include "common/opencl.h"
58#include "control/conf.h"
59#include "control/control.h"
60#include "develop/develop.h"
61#include "develop/imageop.h"
62#include "develop/imageop_gui.h"
63#include "dtgtk/button.h"
64#include "dtgtk/resetlabel.h"
65#include "dtgtk/togglebutton.h"
66
68#include "gui/draw.h"
69#include "gui/gtk.h"
70#include "gui/presets.h"
71#include "iop/iop_api.h"
72
73#include <gdk/gdkkeysyms.h>
74#include <gtk/gtk.h>
75#include <inttypes.h>
76#include <math.h>
77#include <stdlib.h>
78#include <string.h>
79
81
82// Module constants
83#define DT_IOP_BORDERS_ASPECT_COUNT 12
84#define DT_IOP_BORDERS_ASPECT_IMAGE_IDX 0
85#define DT_IOP_BORDERS_ASPECT_CONSTANT_IDX 11
86#define DT_IOP_BORDERS_ASPECT_IMAGE_VALUE 0.0f
87#define DT_IOP_BORDERS_ASPECT_CONSTANT_VALUE -1.0f
88#define DT_IOP_BORDERS_ASPECT_ORIENTATION_AUTO 0
89#define DT_IOP_BORDERS_ASPECT_ORIENTATION_PORTRAIT 1
90#define DT_IOP_BORDERS_ASPECT_ORIENTATION_LANDSCAPE 2
91#define DT_IOP_BORDERS_POSITION_H_COUNT 5
92#define DT_IOP_BORDERS_POSITION_V_COUNT 5
93
95{
96 float color[3]; // border color $DEFAULT: 1.0
97 float aspect; /* aspect ratio of the outer frame w/h
98 $MIN: 1.0 $MAX: 3.0 $DEFAULT: DT_IOP_BORDERS_ASPECT_CONSTANT_VALUE $DESCRIPTION: "aspect ratio" */
99 char aspect_text[20]; /* aspect ratio of the outer frame w/h (user string version)
100 DEFAULT: "constant border" */
101 int aspect_orient; /* aspect ratio orientation
102 $DEFAULT: 0 $DESCRIPTION: "orientation" */
103 float size; /* border width relative to overall frame width
104 $MIN: 0.0 $MAX: 0.5 $DEFAULT: 0.1 $DESCRIPTION: "border size" */
105 float pos_h; /* picture horizontal position ratio into the final image
106 $MIN: 0.0 $MAX: 1.0 $DEFAULT: 0.5 $DESCRIPTION: "horizontal offset" */
107 char pos_h_text[20]; /* picture horizontal position ratio into the final image (user string version)
108 DEFAULT: "1/2" */
109 float pos_v; /* picture vertical position ratio into the final image
110 $MIN: 0.0 $MAX: 1.0 $DEFAULT: 0.5 $DESCRIPTION: "vertical offset"*/
111 char pos_v_text[20]; /* picture vertical position ratio into the final image (user string version)
112 DEFAULT: "1/2" */
113 float frame_size; /* frame line width relative to border width
114 $MIN: 0.0 $MAX: 1.0 $DEFAULT: 0.0 $DESCRIPTION: "frame line size" */
115 float frame_offset; /* frame offset from picture size relative to [border width - frame width]
116 $MIN: 0.0 $MAX: 1.0 $DEFAULT: 0.5 $DESCRIPTION: "frame line offset" */
117 float frame_color[3]; // frame line color $DEFAULT: 0.0
118 gboolean max_border_size; /* the way border size is computed
119 $DEFAULT: TRUE */
121
142
143// ******* Check and update legacy params...(esp. ver 4)
144int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
145 void *new_params, const int new_version)
146{
147 if(old_version == 1 && new_version == 3)
148 {
149 typedef struct dt_iop_borders_params_v1_t
150 {
151 float color[3]; // border color
152 float aspect; // aspect ratio of the outer frame w/h
153 float size; // border width relative to overall frame width
154 } dt_iop_borders_params_v1_t;
155
156 dt_iop_borders_params_v1_t *o = (dt_iop_borders_params_v1_t *)old_params;
159
160 *n = *d; // start with a fresh copy of default parameters
161 memcpy(n->color, o->color, sizeof(o->color));
162 n->aspect = (o->aspect < 1) ? 1 / o->aspect : o->aspect;
163 // no auto orientation in legacy param due to already convert aspect ratio
164 n->aspect_orient = o->aspect > 1 ? DT_IOP_BORDERS_ASPECT_ORIENTATION_LANDSCAPE
166 n->size = fabsf(o->size); // no negative size any more (was for "constant border" detect)
167 n->max_border_size = FALSE;
168 return 0;
169 }
170
171 if(old_version == 2 && new_version == 3)
172 {
173 typedef struct dt_iop_borders_params_v2_t
174 {
175 float color[3]; // border color
176 float aspect; // aspect ratio of the outer frame w/h
177 char aspect_text[20]; // aspect ratio of the outer frame w/h (user string version)
178 int aspect_orient; // aspect ratio orientation
179 float size; // border width relative to overall frame width
180 float pos_h; // picture horizontal position ratio into the final image
181 char pos_h_text[20]; // picture horizontal position ratio into the final image (user string version)
182 float pos_v; // picture vertical position ratio into the final image
183 char pos_v_text[20]; // picture vertical position ratio into the final image (user string version)
184 float frame_size; // frame line width relative to border width
185 float frame_offset; // frame offset from picture size relative to [border width - frame width]
186 float frame_color[3]; // frame line color
187 } dt_iop_borders_params_v2_t;
188
189 dt_iop_borders_params_v2_t *o = (dt_iop_borders_params_v2_t *)old_params;
191
192 memcpy(n, o, sizeof(struct dt_iop_borders_params_v2_t));
193 n->max_border_size = FALSE;
194 return 0;
195 }
196
197 return 1;
198}
199
204
205
207
208
209const char *name()
210{
211 return _("framing");
212}
213
214const char **description(struct dt_iop_module_t *self)
215{
216 return dt_iop_set_description(self, _("add solid borders or margins around the picture"),
217 _("creative"),
218 _("linear or non-linear, RGB, display-referred"),
219 _("geometric, RGB"),
220 _("linear or non-linear, RGB, display-referred"));
221}
222
223
225{
226 return IOP_GROUP_EFFECTS;
227}
228
233
238
240{
241 return IOP_CS_RGB;
242}
243
245 float *const restrict points, size_t points_count)
246{
248
249 const int border_tot_width = (piece->buf_out.width - piece->buf_in.width);
250 const int border_tot_height = (piece->buf_out.height - piece->buf_in.height);
251 const int border_size_t = border_tot_height * d->pos_v;
252 const int border_size_l = border_tot_width * d->pos_h;
253
254 // nothing to be done if parameters are set to neutral values (no top/left border)
255 if (border_size_l == 0 && border_size_t == 0) return 1;
256 __OMP_PARALLEL_FOR_SIMD__(if(points_count > 100) aligned(points:64))
257 for(size_t i = 0; i < points_count * 2; i += 2)
258 {
259 points[i] += border_size_l;
260 points[i + 1] += border_size_t;
261 }
262
263 return 1;
264}
266 float *const restrict points, size_t points_count)
267{
269
270 const int border_tot_width = (piece->buf_out.width - piece->buf_in.width);
271 const int border_tot_height = (piece->buf_out.height - piece->buf_in.height);
272 const int border_size_t = border_tot_height * d->pos_v;
273 const int border_size_l = border_tot_width * d->pos_h;
274
275 // nothing to be done if parameters are set to neutral values (no top/left border)
276 if (border_size_l == 0 && border_size_t == 0) return 1;
277 __OMP_PARALLEL_FOR_SIMD__(if(points_count > 100) aligned(points:64))
278 for(size_t i = 0; i < points_count * 2; i += 2)
279 {
280 points[i] -= border_size_l;
281 points[i + 1] -= border_size_t;
282 }
283
284 return 1;
285}
286
287void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece,
288 const float *const in, float *const out, const dt_iop_roi_t *const roi_in,
289 const dt_iop_roi_t *const roi_out)
290{
291 (void)pipe;
293
294 const int border_tot_width = (piece->buf_out.width - piece->buf_in.width) * roi_in->scale;
295 const int border_tot_height = (piece->buf_out.height - piece->buf_in.height) * roi_in->scale;
296 const int border_size_t = border_tot_height * d->pos_v;
297 const int border_size_l = border_tot_width * d->pos_h;
298 const int border_in_x = MAX(border_size_l - roi_out->x, 0);
299 const int border_in_y = MAX(border_size_t - roi_out->y, 0);
300
301 // fill the image with 0 so that the added border isn't part of the mask
302 dt_iop_image_fill(out, 0.0f, roi_out->width, roi_out->height, 1);
303
304 // blit image inside border and fill the output with previous processed out
306 for(int j = 0; j < roi_in->height; j++)
307 {
308 float *outb = out + (size_t)(j + border_in_y) * roi_out->width + border_in_x;
309 const float *inb = in + (size_t)j * roi_in->width;
310 memcpy(outb, inb, sizeof(float) * roi_in->width);
311 }
312}
313
314// 1st pass: how large would the output be, given this input roi?
315// this is always called with the full buffer before processing.
316void modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
317 struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out,
318 const dt_iop_roi_t *roi_in)
319{
320 *roi_out = *roi_in;
322 const float size = fabsf(d->size);
323 if(size == 0.0f || size >= 1.0f) return;
324
326 {
327 // base computation on the larger border to keep constant size regardless of orientation
328 if(roi_in->width > roi_in->height || !d->max_border_size)
329 {
330 // relative to width, constant for height as well
331 roi_out->width = (float)roi_in->width / (1.0f - size);
332 roi_out->height = roi_in->height + roi_out->width - roi_in->width;
333 }
334 else
335 {
336 // relative to height, constant for width as well
337 roi_out->height = (float)roi_in->height / (1.0f - size);
338 roi_out->width = roi_in->width + roi_out->height - roi_in->height;
339 }
340 }
341 else
342 {
343 const float image_aspect = roi_in->width / (float)roi_in->height;
344 float aspect = (d->aspect == DT_IOP_BORDERS_ASPECT_IMAGE_VALUE) ? image_aspect : d->aspect;
345 if(aspect <= 0.0f) return;
346
347 if(d->aspect_orient == DT_IOP_BORDERS_ASPECT_ORIENTATION_AUTO)
348 aspect = ((image_aspect < 1.0f) != (aspect < 1.0f)) ? 1.0f / aspect : aspect;
349 else if(d->aspect_orient == DT_IOP_BORDERS_ASPECT_ORIENTATION_LANDSCAPE)
350 aspect = (aspect < 1.0f) ? 1.0f / aspect : aspect;
351 else if(d->aspect_orient == DT_IOP_BORDERS_ASPECT_ORIENTATION_PORTRAIT)
352 aspect = (aspect > 1.0f) ? 1.0f / aspect : aspect;
353
354 const float inv_size = 1.0f / (1.0f - size);
355 roi_out->width = (float)roi_in->width * inv_size;
356 roi_out->height = (float)roi_out->width / aspect;
357
358 // if height constraint is tighter, use it as the driver axis instead
359 const float min_height = (float)roi_in->height * inv_size;
360 if(roi_out->height < min_height)
361 {
362 roi_out->height = min_height;
363 roi_out->width = roi_out->height * aspect;
364 }
365 }
366}
367
368// 2nd pass: which roi would this operation need as input to fill the given output region?
369void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
370 struct dt_dev_pixelpipe_iop_t *piece,
371 const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
372{
374 *roi_in = *roi_out;
375 const int bw = (piece->buf_out.width - piece->buf_in.width) * roi_out->scale;
376 const int bh = (piece->buf_out.height - piece->buf_in.height) * roi_out->scale;
377
378 // don't request outside image (no px for borders)
379 roi_in->x = MAX(roi_out->x - bw * d->pos_h, 0);
380 roi_in->y = MAX(roi_out->y - bh * d->pos_v, 0);
381 // subtract upper left border from dimensions
382 roi_in->width -= MAX(bw * d->pos_h - roi_out->x, 0);
383 roi_in->height -= MAX(bh * d->pos_v - roi_out->y, 0);
384
385 // subtract lower right border from dimensions
386 roi_in->width -= roi_out->scale
387 * MAX((roi_in->x + roi_in->width) / roi_out->scale - (piece->buf_in.width), 0);
388 roi_in->height -= roi_out->scale
389 * MAX((roi_in->y + roi_in->height) / roi_out->scale - (piece->buf_in.height), 0);
390 // don't request nothing or outside roi
391 roi_in->width = MIN(roi_out->scale * piece->buf_in.width, MAX(1, roi_in->width));
392 roi_in->height = MIN(roi_out->scale * piece->buf_in.height, MAX(1, roi_in->height));
393 // FIXME: clamping to 1 leads to a one-pixel visual glitch if the right/bottom border completely fills the
394 // FIXME: viewport, but changing it to 0 breaks all of the tiling_callback functions with a division by zero
395}
396
398{
401 int border_top; // 0..bt is rows of top border outside the frameline
402 int fl_top; //bt..ft is the top frameline
403 int image_top; //ft..it is the top border inside the frameline
404 int border_left; // 0..bl is columns of left border outside the frameline
405 int fl_left; //bl..fl is the left frameline
406 int image_left; //fl..il is the left border inside the frameline
407 int image_right; //il..ir is the actual image area
408 int fl_right; //ir..fr is the right border inside the frameline
409 int border_right; //fr..br is the right frameeline
410 int width; //br..width is the right border outside the frameline
411 int image_bot; //it..ib is the actual image area
412 int fl_bot; //ib..fb is the bottom border inside the frameline
413 int border_bot; //fb..bt is the frameline
414 int height; //bt..height is the bottom border outside the frameline
415 int stride; // width of input roi
416};
417
418// this will be called from inside an OpenMP parallel section, so no need to parallelize further
419static inline void set_pixels(float *buf, const dt_aligned_pixel_t color, const int npixels)
420{
421 for (int i = 0; i < npixels; i++)
422 {
423 __OMP_SIMD__(aligned(buf, color : 16))
424 for (int c = 0; c < 4; c++)
425 {
426 buf[4*i+c] = color[c];
427 }
428 }
429}
430
431// this will be called from inside an OpenMP parallel section, so no need to parallelize further
432static inline void copy_pixels(float *out, const float *const in, const int npixels)
433{
434 for (int i = 0; i < npixels; i++)
435 {
436 __OMP_SIMD__(aligned(in, out : 16))
437 for (int c = 0; c < 4; c++)
438 {
439 out[4*i+c] = in[4*i+c];
440 }
441 }
442}
443
445void copy_image_with_border(float *out, const float *const in, const struct border_positions_t *binfo)
446{
447 const int image_width = binfo->image_right - binfo->image_left;
449 for (size_t row = 0; row < binfo->height; row++)
450 {
451 float *outrow = out + 4 * row * binfo->width;
452 if (row < binfo->border_top || row >= binfo->border_bot)
453 {
454 // top/bottom border outside the frameline: entirely the border color
455 set_pixels(outrow, binfo->bcolor, binfo->width);
456 }
457 else if (row < binfo->fl_top || row >= binfo->fl_bot)
458 {
459 // top/bottom frameline
460 set_pixels(outrow, binfo->bcolor, binfo->border_left);
461 set_pixels(outrow + 4*binfo->border_left, binfo->flcolor, binfo->border_right - binfo->border_left);
462 set_pixels(outrow + 4*binfo->border_right, binfo->bcolor, binfo->width - binfo->border_right);
463 }
464 else if (row < binfo->image_top || row >= binfo->image_bot)
465 {
466 // top/bottom border inside the frameline
467 set_pixels(outrow, binfo->bcolor, binfo->border_left);
468 set_pixels(outrow + 4*binfo->border_left, binfo->flcolor, binfo->fl_left - binfo->border_left);
469 set_pixels(outrow + 4*binfo->fl_left, binfo->bcolor, binfo->fl_right - binfo->fl_left);
470 set_pixels(outrow + 4*binfo->fl_right, binfo->flcolor, binfo->border_right - binfo->fl_right);
471 set_pixels(outrow + 4*binfo->border_right, binfo->bcolor, binfo->width - binfo->border_right);
472 }
473 else
474 {
475 // image area: set left border (w/optional frame line), copy image row, set right border (w/optional frame line)
476 // set outer border
477 set_pixels(outrow, binfo->bcolor, binfo->border_left);
478 if (binfo->image_left > binfo->border_left)
479 {
480 // we have a frameline, so set it and the inner border
481 set_pixels(outrow + 4*binfo->border_left, binfo->flcolor, binfo->fl_left - binfo->border_left);
482 set_pixels(outrow + 4*binfo->fl_left, binfo->bcolor, binfo->image_left - binfo->fl_left);
483 }
484 // copy image row
485 copy_pixels(outrow + 4*binfo->image_left, in + 4 * (row - binfo->image_top) * binfo->stride, image_width);
486 // set right border
487 set_pixels(outrow + 4*binfo->image_right, binfo->bcolor, binfo->fl_right - binfo->image_right);
488 if (binfo->width > binfo->fl_right)
489 {
490 // we have a frameline, so set it and the outer border
491 set_pixels(outrow + 4*binfo->fl_right, binfo->flcolor, binfo->border_right - binfo->fl_right);
492 set_pixels(outrow + 4*binfo->border_right, binfo->bcolor, binfo->width - binfo->border_right);
493 }
494 }
495 }
496
497}
498
499int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
500 void *const ovoid)
501{
502 const dt_iop_roi_t *const roi_in = &piece->roi_in;
503 const dt_iop_roi_t *const roi_out = &piece->roi_out;
504 const dt_iop_borders_data_t *const d = (dt_iop_borders_data_t *)piece->data;
505
506 const int border_tot_width = (piece->buf_out.width - piece->buf_in.width) * roi_in->scale;
507 const int border_tot_height = (piece->buf_out.height - piece->buf_in.height) * roi_in->scale;
508 const int border_size_t = border_tot_height * d->pos_v;
509 const int border_size_b = border_tot_height - border_size_t;
510 const int border_size_l = border_tot_width * d->pos_h;
511 const int border_size_r = border_tot_width - border_size_l;
512 const int border_in_x = MAX(border_size_l - roi_out->x, 0);
513 const int border_in_y = MAX(border_size_t - roi_out->y, 0);
514
515 // compute frame line parameters
516 const int border_min_size = MIN(MIN(border_size_t, border_size_b), MIN(border_size_l, border_size_r));
517 const int frame_size = border_min_size * d->frame_size;
518
519 const int b_in_x = CLAMP(border_in_x, 0, roi_out->width - 1);
520 struct border_positions_t binfo =
521 { .bcolor = { d->color[0], d->color[1], d->color[2], 1.0f },
522 .flcolor = { d->frame_color[0], d->frame_color[1], d->frame_color[2], 1.0f },
523 .border_top = border_in_y,
524 .fl_top = border_in_y,
525 .image_top = border_in_y,
526 .border_left = b_in_x,
527 .fl_left = b_in_x,
528 .image_left = b_in_x,
529 .image_right = b_in_x + roi_in->width,
530 .fl_right = roi_out->width,
531 .border_right = roi_out->width,
532 .width = roi_out->width,
533 .image_bot = border_in_y + roi_in->height,
534 .fl_bot = roi_out->height,
535 .border_bot = roi_out->height,
536 .height = roi_out->height,
537 .stride = roi_in->width
538 };
539 if (frame_size > 0)
540 {
541 const int image_lx = border_size_l - roi_out->x;
542 const int image_ty = border_size_t - roi_out->y;
543 const int frame_space = border_min_size - frame_size;
544 const int frame_offset = frame_space * d->frame_offset;
545 const int frame_tl_in_x = MAX(border_in_x - frame_offset, 0);
546 const int frame_tl_out_x = MAX(frame_tl_in_x - frame_size, 0);
547 const int frame_tl_in_y = MAX(border_in_y - frame_offset, 0);
548 const int frame_tl_out_y = MAX(frame_tl_in_y - frame_size, 0);
549 binfo.border_top = frame_tl_out_y;
550 binfo.fl_top = frame_tl_in_y;
551 binfo.border_left = CLAMP(frame_tl_out_x, 0, roi_out->width);
552 binfo.fl_left = CLAMP(frame_tl_in_x, 0, roi_out->width);
553 const int frame_in_width = floor((piece->buf_in.width * roi_in->scale) + frame_offset * 2);
554 const int frame_in_height = floor((piece->buf_in.height * roi_in->scale) + frame_offset * 2);
555 const int frame_out_width = frame_in_width + frame_size * 2;
556 const int frame_out_height = frame_in_height + frame_size * 2;
557 const int frame_br_in_x = CLAMP(image_lx - frame_offset + frame_in_width - 1, 0, roi_out->width - 1);
558 const int frame_br_in_y = CLAMP(image_ty - frame_offset + frame_in_height - 1, 0, roi_out->height - 1);
559 // ... if 100% frame_offset we ensure frame_line "stick" the out border
560 const int frame_br_out_x
561 = (d->frame_offset == 1.0f && (border_min_size == MIN(border_size_l, border_size_r)))
562 ? (roi_out->width)
563 : CLAMP(image_lx - frame_offset - frame_size + frame_out_width - 1, 0, roi_out->width - 1);
564 const int frame_br_out_y
565 = (d->frame_offset == 1.0f && (border_min_size == MIN(border_size_t, border_size_b)))
566 ? (roi_out->height)
567 : CLAMP(image_ty - frame_offset - frame_size + frame_out_height - 1, 0, roi_out->height - 1);
568 binfo.fl_right = frame_br_in_x + 1; // need end+1 for these coordinates
569 binfo.border_right = frame_br_out_x + 1;
570 binfo.fl_bot = frame_br_in_y + 1;
571 binfo.border_bot = frame_br_out_y + 1;
572 }
573 copy_image_with_border((float*)ovoid, (const float*)ivoid, &binfo);
574 return 0;
575}
576
577#ifdef HAVE_OPENCL
578int 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)
579{
580 const dt_iop_roi_t *const roi_in = &piece->roi_in;
581 const dt_iop_roi_t *const roi_out = &piece->roi_out;
584
585 cl_int err = -999;
586 const int devid = pipe->devid;
587
588 const int width = roi_out->width;
589 const int height = roi_out->height;
590
591 const int border_tot_width = (piece->buf_out.width - piece->buf_in.width) * roi_in->scale;
592 const int border_tot_height = (piece->buf_out.height - piece->buf_in.height) * roi_in->scale;
593 const int border_size_t = border_tot_height * d->pos_v;
594 const int border_size_b = border_tot_height - border_size_t;
595 const int border_size_l = border_tot_width * d->pos_h;
596 const int border_size_r = border_tot_width - border_size_l;
597 const int border_in_x = MAX(border_size_l - roi_out->x, 0);
598 const int border_in_y = MAX(border_size_t - roi_out->y, 0);
599
600 // ----- Filling border
601 const float col[4] = { d->color[0], d->color[1], d->color[2], 1.0f };
602 size_t sizes[2] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid) };
603 const int zero = 0;
604 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 0, sizeof(cl_mem), &dev_out);
605 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 1, sizeof(int), &zero);
606 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 2, sizeof(int), &zero);
607 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 3, sizeof(int), &width);
608 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 4, sizeof(int), &height);
609 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 5, 4 * sizeof(float), &col);
610 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_borders_fill, sizes);
611 if(err != CL_SUCCESS) goto error;
612
613 // ----- Frame line
614 const int border_min_size = MIN(MIN(border_size_t, border_size_b), MIN(border_size_l, border_size_r));
615 const int frame_size = border_min_size * d->frame_size;
616 if(frame_size != 0)
617 {
618 const float col_frame[4] = { d->frame_color[0], d->frame_color[1], d->frame_color[2], 1.0f };
619 const int image_lx = border_size_l - roi_out->x;
620 const int image_ty = border_size_t - roi_out->y;
621 const int frame_space = border_min_size - frame_size;
622 const int frame_offset = frame_space * d->frame_offset;
623 const int frame_tl_in_x = MAX(border_in_x - frame_offset, 0);
624 const int frame_tl_out_x = MAX(frame_tl_in_x - frame_size, 0);
625 const int frame_tl_in_y = MAX(border_in_y - frame_offset, 0);
626 const int frame_tl_out_y = MAX(frame_tl_in_y - frame_size, 0);
627 const int frame_in_width = floor((piece->buf_in.width * roi_in->scale) + frame_offset * 2);
628 const int frame_in_height = floor((piece->buf_in.height * roi_in->scale) + frame_offset * 2);
629 const int frame_out_width = frame_in_width + frame_size * 2;
630 const int frame_out_height = frame_in_height + frame_size * 2;
631 const int frame_br_in_x = CLAMP(image_lx - frame_offset + frame_in_width - 1, 0, roi_out->width - 1);
632 const int frame_br_in_y = CLAMP(image_ty - frame_offset + frame_in_height - 1, 0, roi_out->height - 1);
633 // ... if 100% frame_offset we ensure frame_line "stick" the out border
634 const int frame_br_out_x
635 = (d->frame_offset == 1.0f && (border_min_size == MIN(border_size_l, border_size_r)))
636 ? (roi_out->width)
637 : CLAMP(image_lx - frame_offset - frame_size + frame_out_width - 1, 0, roi_out->width);
638 const int frame_br_out_y
639 = (d->frame_offset == 1.0f && (border_min_size == MIN(border_size_t, border_size_b)))
640 ? (roi_out->height)
641 : CLAMP(image_ty - frame_offset - frame_size + frame_out_height - 1, 0, roi_out->height);
642
643 const int roi_frame_in_width = frame_br_in_x - frame_tl_in_x;
644 const int roi_frame_in_height = frame_br_in_y - frame_tl_in_y;
645 const int roi_frame_out_width = frame_br_out_x - frame_tl_out_x;
646 const int roi_frame_out_height = frame_br_out_y - frame_tl_out_y;
647
648 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 0, sizeof(cl_mem), &dev_out);
649 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 1, sizeof(int), &frame_tl_out_x);
650 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 2, sizeof(int), &frame_tl_out_y);
651 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 3, sizeof(int), &roi_frame_out_width);
652 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 4, sizeof(int), &roi_frame_out_height);
653 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 5, 4 * sizeof(float), &col_frame);
654 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_borders_fill, sizes);
655 if(err != CL_SUCCESS) goto error;
656
657 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 0, sizeof(cl_mem), &dev_out);
658 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 1, sizeof(int), &frame_tl_in_x);
659 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 2, sizeof(int), &frame_tl_in_y);
660 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 3, sizeof(int), &roi_frame_in_width);
661 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 4, sizeof(int), &roi_frame_in_height);
662 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 5, 4 * sizeof(float), &col);
663 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_borders_fill, sizes);
664 if(err != CL_SUCCESS) goto error;
665 }
666
667 size_t iorigin[] = { 0, 0, 0 };
668 size_t oorigin[] = { border_in_x, border_in_y, 0 };
669 size_t region[] = { roi_in->width, roi_in->height, 1 };
670
671 // copy original input from dev_in -> dev_out as starting point
672 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, iorigin, oorigin, region);
673 if(err != CL_SUCCESS) goto error;
674
675 return TRUE;
676
677error:
678 dt_print(DT_DEBUG_OPENCL, "[opencl_borders] couldn't enqueue kernel! %d\n", err);
679 return FALSE;
680}
681#endif
682
683
685{
686 const int program = 2; // basic.cl from programs.conf
689 module->data = gd;
690 gd->kernel_borders_fill = dt_opencl_create_kernel(program, "borders_fill");
691}
692
693
700
701
709
711{
713 piece->data_size = sizeof(dt_iop_borders_data_t);
714}
715
717{
718 dt_free_align(piece->data);
719 piece->data = NULL;
720}
721
723{
724 dt_iop_borders_params_t p = (dt_iop_borders_params_t){ { 1.0f, 1.0f, 1.0f },
725 3.0f / 2.0f,
726 "3:2",
727 0,
728 0.1f,
729 0.5f,
730 "1/2",
731 0.5f,
732 "1/2",
733 0.0f,
734 0.5f,
735 { 0.0f, 0.0f, 0.0f },
736 TRUE };
737 dt_gui_presets_add_generic(_("15:10 postcard white"), self->op,
738 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_NONE);
739
740 p.color[0] = p.color[1] = p.color[2] = 0.0f;
741 p.frame_color[0] = p.frame_color[1] = p.frame_color[2] = 1.0f;
742 dt_gui_presets_add_generic(_("15:10 postcard black"), self->op,
743 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_NONE);
744}
745
747{
750
751 if(fabsf(p->color[0] - self->picked_color[0]) < 0.0001f
752 && fabsf(p->color[1] - self->picked_color[1]) < 0.0001f
753 && fabsf(p->color[2] - self->picked_color[2]) < 0.0001f)
754 {
755 // interrupt infinite loops
756 return;
757 }
758
759 if(fabsf(p->frame_color[0] - self->picked_color[0]) < 0.0001f
760 && fabsf(p->frame_color[1] - self->picked_color[1]) < 0.0001f
761 && fabsf(p->frame_color[2] - self->picked_color[2]) < 0.0001f)
762 {
763 // interrupt infinite loops
764 return;
765 }
766
767 GdkRGBA c = (GdkRGBA){.red = self->picked_color[0],
768 .green = self->picked_color[1],
769 .blue = self->picked_color[2],
770 .alpha = 1.0 };
771
772 if(picker == g->frame_picker)
773 {
774 p->frame_color[0] = self->picked_color[0];
775 p->frame_color[1] = self->picked_color[1];
776 p->frame_color[2] = self->picked_color[2];
777 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->frame_colorpick), &c);
778 }
779 else if(picker == g->border_picker)
780 {
781 p->color[0] = self->picked_color[0];
782 p->color[1] = self->picked_color[1];
783 p->color[2] = self->picked_color[2];
784 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->colorpick), &c);
785 }
786
788}
789
790static void aspect_changed(GtkWidget *combo, dt_iop_module_t *self)
791{
794 const int which = dt_bauhaus_combobox_get(combo);
795 const char *text = dt_bauhaus_combobox_get_text(combo);
796 if(which == dt_bauhaus_combobox_length(combo)-1)
797 {
798 g_strlcpy(p->aspect_text, text, sizeof(p->aspect_text));
799 }
800 else if(which < DT_IOP_BORDERS_ASPECT_COUNT)
801 {
802 g_strlcpy(p->aspect_text, text, sizeof(p->aspect_text));
803 p->aspect = g->aspect_ratios[which];
805 dt_bauhaus_slider_set(g->aspect_slider,p->aspect);
807 }
810}
811
813{
816 const int which = dt_bauhaus_combobox_get(combo);
817 const char *text = dt_bauhaus_combobox_get_text(combo);
818 if(which == dt_bauhaus_combobox_length(combo)-1)
819 {
820 g_strlcpy(p->aspect_text, text, sizeof(p->aspect_text));
821 }
822 else if(which < DT_IOP_BORDERS_POSITION_H_COUNT)
823 {
824 g_strlcpy(p->pos_h_text, text, sizeof(p->pos_h_text));
825 p->pos_h = g->pos_h_ratios[which];
827 dt_bauhaus_slider_set(g->pos_h_slider,p->pos_h);
829 }
832}
833
835{
838 const int which = dt_bauhaus_combobox_get(combo);
839 const char *text = dt_bauhaus_combobox_get_text(combo);
840 if(which == dt_bauhaus_combobox_length(combo)-1)
841 {
842 g_strlcpy(p->aspect_text, text, sizeof(p->aspect_text));
843 }
844 else if(which < DT_IOP_BORDERS_POSITION_V_COUNT)
845 {
846 g_strlcpy(p->pos_v_text, text, sizeof(p->pos_v_text));
847 p->pos_v = g->pos_v_ratios[which];
849 dt_bauhaus_slider_set(g->pos_v_slider,p->pos_v);
851 }
854}
855
856void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
857{
859
860 if (w == g->aspect_slider)
861 {
863 }
864 else if(w == g->pos_h_slider)
865 {
867 }
868 else if(w == g->pos_v_slider)
869 {
871 }
872}
873
874static void colorpick_color_set(GtkColorButton *widget, dt_iop_module_t *self)
875{
876 if(dt_gui_widgets_suppressed()) return;
878
879 // turn off the other color picker so that this tool actually works ...
881
882 GdkRGBA c;
883 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &c);
884 p->color[0] = c.red;
885 p->color[1] = c.green;
886 p->color[2] = c.blue;
887
889}
890
891
892static void frame_colorpick_color_set(GtkColorButton *widget, dt_iop_module_t *self)
893{
894 if(dt_gui_widgets_suppressed()) return;
896
897 // turn off the other color picker so that this tool actually works ...
899
900 GdkRGBA c;
901 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &c);
902 p->frame_color[0] = c.red;
903 p->frame_color[1] = c.green;
904 p->frame_color[2] = c.blue;
905
907}
908
909void gui_update(struct dt_iop_module_t *self)
910{
913
914// FIXME by hand
915 // ----- Aspect
916 int k = 0;
918 {
919 if(fabsf(p->aspect - g->aspect_ratios[k]) < 0.01f)
920 {
921 dt_bauhaus_combobox_set(g->aspect, k);
922 break;
923 }
924 }
926 {
927 dt_bauhaus_combobox_set(g->aspect, k);
928 }
929
930 // ----- Position H
931 for(k = 0; k < DT_IOP_BORDERS_POSITION_H_COUNT; k++)
932 {
933 if(fabsf(p->pos_h - g->pos_h_ratios[k]) < 0.01f)
934 {
935 dt_bauhaus_combobox_set(g->pos_h, k);
936 break;
937 }
938 }
940 {
941 dt_bauhaus_combobox_set(g->pos_h, k);
942 }
943
944 // ----- Position V
945 for(k = 0; k < DT_IOP_BORDERS_POSITION_V_COUNT; k++)
946 {
947 if(fabsf(p->pos_v - g->pos_v_ratios[k]) < 0.01f)
948 {
949 dt_bauhaus_combobox_set(g->pos_v, k);
950 break;
951 }
952 }
954 {
955 dt_bauhaus_combobox_set(g->pos_v, k);
956 }
957
958 // ----- Border Color
959 GdkRGBA c = (GdkRGBA){.red = p->color[0], .green = p->color[1], .blue = p->color[2], .alpha = 1.0 };
960 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->colorpick), &c);
961
962 // ----- Frame Color
963 GdkRGBA fc = (GdkRGBA){
964 .red = p->frame_color[0], .green = p->frame_color[1], .blue = p->frame_color[2], .alpha = 1.0
965 };
966 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->frame_colorpick), &fc);
967}
968
969static void gui_init_aspect(struct dt_iop_module_t *self)
970{
972
973 dt_bauhaus_combobox_add(g->aspect, _("image"));
974 dt_bauhaus_combobox_add(g->aspect, _("3:1"));
975 dt_bauhaus_combobox_add(g->aspect, _("95:33"));
976 dt_bauhaus_combobox_add(g->aspect, _("2:1"));
977 dt_bauhaus_combobox_add(g->aspect, _("16:9"));
978 dt_bauhaus_combobox_add(g->aspect, _("golden cut"));
979 dt_bauhaus_combobox_add(g->aspect, _("3:2"));
980 dt_bauhaus_combobox_add(g->aspect, _("A4"));
981 dt_bauhaus_combobox_add(g->aspect, _("DIN"));
982 dt_bauhaus_combobox_add(g->aspect, _("4:3"));
983 dt_bauhaus_combobox_add(g->aspect, _("square"));
984 dt_bauhaus_combobox_add(g->aspect, _("constant border"));
985 dt_bauhaus_combobox_add(g->aspect, _("custom..."));
986
989 int i = 1;
990 g->aspect_ratios[i++] = 3.0f;
991 g->aspect_ratios[i++] = 95.0f / 33.0f;
992 g->aspect_ratios[i++] = 2.0f;
993 g->aspect_ratios[i++] = 16.0f / 9.0f;
994 g->aspect_ratios[i++] = PHI;
995 g->aspect_ratios[i++] = 3.0f / 2.0f;
996 g->aspect_ratios[i++] = 297.0f / 210.0f;
997 g->aspect_ratios[i++] = sqrtf(2.0f);
998 g->aspect_ratios[i++] = 4.0f / 3.0f;
999 g->aspect_ratios[i++] = 1.0f;
1000}
1001
1002static void gui_init_positions(struct dt_iop_module_t *self)
1003{
1005
1006 dt_bauhaus_combobox_add(g->pos_h, _("center"));
1007 dt_bauhaus_combobox_add(g->pos_h, _("1/3"));
1008 dt_bauhaus_combobox_add(g->pos_h, _("3/8"));
1009 dt_bauhaus_combobox_add(g->pos_h, _("5/8"));
1010 dt_bauhaus_combobox_add(g->pos_h, _("2/3"));
1011 dt_bauhaus_combobox_add(g->pos_h, _("custom..."));
1012 dt_bauhaus_combobox_add(g->pos_v, _("center"));
1013 dt_bauhaus_combobox_add(g->pos_v, _("1/3"));
1014 dt_bauhaus_combobox_add(g->pos_v, _("3/8"));
1015 dt_bauhaus_combobox_add(g->pos_v, _("5/8"));
1016 dt_bauhaus_combobox_add(g->pos_v, _("2/3"));
1017 dt_bauhaus_combobox_add(g->pos_v, _("custom..."));
1018
1019 int i = 0;
1020 g->pos_h_ratios[i++] = 0.5f;
1021 g->pos_h_ratios[i++] = 1.0f / 3.0f;
1022 g->pos_h_ratios[i++] = 3.0f / 8.0f;
1023 g->pos_h_ratios[i++] = 5.0f / 8.0f;
1024 g->pos_h_ratios[i++] = 2.0f / 3.0f;
1025 i = 0;
1026 g->pos_v_ratios[i++] = 0.5f;
1027 g->pos_v_ratios[i++] = 1.0f / 3.0f;
1028 g->pos_v_ratios[i++] = 3.0f / 8.0f;
1029 g->pos_v_ratios[i++] = 5.0f / 8.0f;
1030 g->pos_v_ratios[i++] = 2.0f / 3.0f;
1031}
1032
1033void gui_init(struct dt_iop_module_t *self)
1034{
1037
1038 g->size = dt_bauhaus_slider_from_params(self, "size");
1040 dt_bauhaus_slider_set_format(g->size, "%");
1041 gtk_widget_set_tooltip_text(g->size, _("size of the border in percent of the full image"));
1042
1045 dt_bauhaus_widget_set_label(g->aspect, N_("aspect"));
1046 gtk_box_pack_start(GTK_BOX(self->widget), g->aspect, TRUE, TRUE, 0);
1047 gui_init_aspect(self);
1048 g_signal_connect(G_OBJECT(g->aspect), "value-changed", G_CALLBACK(aspect_changed), self);
1049 gtk_widget_set_tooltip_text(g->aspect, _("select the aspect ratio or right click and type your own (w:h)"));
1050 g->aspect_slider = dt_bauhaus_slider_from_params(self, "aspect");
1051 gtk_widget_set_tooltip_text(g->aspect_slider, _("set the custom aspect ratio"));
1052
1053 g->aspect_orient = dt_bauhaus_combobox_from_params(self, "aspect_orient");
1054 dt_bauhaus_combobox_add(g->aspect_orient, _("auto"));
1055 dt_bauhaus_combobox_add(g->aspect_orient, _("portrait"));
1056 dt_bauhaus_combobox_add(g->aspect_orient, _("landscape"));
1057 gtk_widget_set_tooltip_text(g->aspect_orient, _("aspect ratio orientation of the image with border"));
1058
1061 dt_bauhaus_widget_set_label(g->pos_h, N_("horizontal position"));
1062 gtk_box_pack_start(GTK_BOX(self->widget), g->pos_h, TRUE, TRUE, 0);
1063 g_signal_connect(G_OBJECT(g->pos_h), "value-changed", G_CALLBACK(position_h_changed), self);
1064 gtk_widget_set_tooltip_text(g->pos_h, _("select the horizontal position ratio relative to top "
1065 "or right click and type your own (y:h)"));
1066 g->pos_h_slider = dt_bauhaus_slider_from_params(self, "pos_h");
1067 gtk_widget_set_tooltip_text(g->pos_h_slider, _("custom horizontal position"));
1068
1071 dt_bauhaus_widget_set_label(g->pos_v, N_("vertical position"));
1072 gtk_box_pack_start(GTK_BOX(self->widget), g->pos_v, TRUE, TRUE, 0);
1073 g_signal_connect(G_OBJECT(g->pos_v), "value-changed", G_CALLBACK(position_v_changed), self);
1074 gtk_widget_set_tooltip_text(g->pos_v, _("select the vertical position ratio relative to left "
1075 "or right click and type your own (x:w)"));
1076 g->pos_v_slider = dt_bauhaus_slider_from_params(self, "pos_v");
1077 gtk_widget_set_tooltip_text(g->pos_v_slider, _("custom vertical position"));
1078
1079 gui_init_positions(self);
1080
1081 g->frame_size = dt_bauhaus_slider_from_params(self, "frame_size");
1082 dt_bauhaus_slider_set_digits(g->frame_size, 4);
1083 dt_bauhaus_slider_set_format(g->frame_size, "%");
1084 gtk_widget_set_tooltip_text(g->frame_size, _("size of the frame line in percent of min border width"));
1085
1086 g->frame_offset = dt_bauhaus_slider_from_params(self, "frame_offset");
1087 dt_bauhaus_slider_set_digits(g->frame_offset, 4);
1088 dt_bauhaus_slider_set_format(g->frame_offset, "%");
1089 gtk_widget_set_tooltip_text(g->frame_offset, _("offset of the frame line beginning on picture side"));
1090
1091 GdkRGBA color = (GdkRGBA){.red = p->color[0], .green = p->color[1], .blue = p->color[2], .alpha = 1.0 };
1092
1093 GtkWidget *label, *box;
1094
1095 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1096 label = dtgtk_reset_label_new(_("border color"), self, &p->color, 3 * sizeof(float));
1097 gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
1098 g->colorpick = gtk_color_button_new_with_rgba(&color);
1099 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(g->colorpick), FALSE);
1100 gtk_color_button_set_title(GTK_COLOR_BUTTON(g->colorpick), _("select border color"));
1101 g_signal_connect(G_OBJECT(g->colorpick), "color-set", G_CALLBACK(colorpick_color_set), self);
1102 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(g->colorpick), FALSE, TRUE, 0);
1103 g->border_picker = dt_color_picker_new(self, DT_COLOR_PICKER_POINT, box);
1104 gtk_widget_set_tooltip_text(GTK_WIDGET(g->border_picker), _("pick border color from image"));
1105 gtk_box_pack_start(GTK_BOX(self->widget), box, TRUE, TRUE, 0);
1106
1107 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1108 label = dtgtk_reset_label_new(_("frame line color"), self, &p->color, 3 * sizeof(float));
1109 gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
1110 g->frame_colorpick = gtk_color_button_new_with_rgba(&color);
1111 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(g->frame_colorpick), FALSE);
1112 gtk_color_button_set_title(GTK_COLOR_BUTTON(g->frame_colorpick), _("select frame line color"));
1113 g_signal_connect(G_OBJECT(g->frame_colorpick), "color-set", G_CALLBACK(frame_colorpick_color_set), self);
1114 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(g->frame_colorpick), FALSE, TRUE, 0);
1115 g->frame_picker = dt_color_picker_new(self, DT_COLOR_PICKER_POINT, box);
1116 gtk_widget_set_tooltip_text(GTK_WIDGET(g->frame_picker), _("pick frame line color from image"));
1117 gtk_box_pack_start(GTK_BOX(self->widget), box, TRUE, TRUE, 0);
1118}
1119
1120
1122{
1123 dt_iop_default_init(self);
1124
1125 dt_iop_borders_params_t *defaults = self->default_params;
1126
1127 g_strlcpy(defaults->aspect_text, "constant border", sizeof(defaults->aspect_text));
1128 g_strlcpy(defaults->pos_h_text, "1/2", sizeof(defaults->pos_h_text));
1129 g_strlcpy(defaults->pos_v_text, "1/2", sizeof(defaults->pos_v_text));
1130}
1131
1132// clang-format off
1133// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1134// vim: shiftwidth=2 expandtab tabstop=2 cindent
1135// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1136// clang-format on
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:3549
void dt_bauhaus_combobox_set_editable(GtkWidget *widget, int editable)
Definition bauhaus.c:2077
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2350
int dt_bauhaus_combobox_length(GtkWidget *widget)
Definition bauhaus.c:2158
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
Definition bauhaus.c:2165
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3537
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2304
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1656
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1845
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3613
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2019
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ DEVELOP_BLEND_CS_NONE
Definition blend.h:56
int operation_tags()
Definition borders.c:229
#define DT_IOP_BORDERS_ASPECT_COUNT
Definition borders.c:83
static void position_v_changed(GtkWidget *combo, dt_iop_module_t *self)
Definition borders.c:834
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 borders.c:702
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)
Definition borders.c:287
const char ** description(struct dt_iop_module_t *self)
Definition borders.c:214
int default_group()
Definition borders.c:224
int distort_backtransform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *const restrict points, size_t points_count)
Definition borders.c:265
static void gui_init_positions(struct dt_iop_module_t *self)
Definition borders.c:1002
int distort_transform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *const restrict points, size_t points_count)
Definition borders.c:244
static void colorpick_color_set(GtkColorButton *widget, dt_iop_module_t *self)
Definition borders.c:874
#define DT_IOP_BORDERS_POSITION_H_COUNT
Definition borders.c:91
struct dt_iop_borders_params_t dt_iop_borders_data_t
Definition borders.c:206
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition borders.c:710
static void position_h_changed(GtkWidget *combo, dt_iop_module_t *self)
Definition borders.c:812
const char * name()
Definition borders.c:209
void gui_update(struct dt_iop_module_t *self)
Definition borders.c:909
static void gui_init_aspect(struct dt_iop_module_t *self)
Definition borders.c:969
static void aspect_changed(GtkWidget *combo, dt_iop_module_t *self)
Definition borders.c:790
void gui_init(struct dt_iop_module_t *self)
Definition borders.c:1033
__DT_CLONE_TARGETS__ void copy_image_with_border(float *out, const float *const in, const struct border_positions_t *binfo)
Definition borders.c:445
#define DT_IOP_BORDERS_POSITION_V_COUNT
Definition borders.c:92
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition borders.c:856
void cleanup_global(dt_iop_module_so_t *module)
Definition borders.c:694
static void set_pixels(float *buf, const dt_aligned_pixel_t color, const int npixels)
Definition borders.c:419
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition borders.c:239
#define DT_IOP_BORDERS_ASPECT_ORIENTATION_AUTO
Definition borders.c:88
int flags()
Definition borders.c:234
#define DT_IOP_BORDERS_ASPECT_CONSTANT_VALUE
Definition borders.c:87
static void copy_pixels(float *out, const float *const in, const int npixels)
Definition borders.c:432
void init_presets(dt_iop_module_so_t *self)
Definition borders.c:722
static void frame_colorpick_color_set(GtkColorButton *widget, dt_iop_module_t *self)
Definition borders.c:892
void init(dt_iop_module_t *self)
Definition borders.c:1121
#define DT_IOP_BORDERS_ASPECT_ORIENTATION_LANDSCAPE
Definition borders.c:90
#define DT_IOP_BORDERS_ASPECT_ORIENTATION_PORTRAIT
Definition borders.c:89
#define DT_IOP_BORDERS_ASPECT_CONSTANT_IDX
Definition borders.c:85
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 borders.c:499
#define DT_IOP_BORDERS_ASPECT_IMAGE_IDX
Definition borders.c:84
#define DT_IOP_BORDERS_ASPECT_IMAGE_VALUE
Definition borders.c:86
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition borders.c:716
void init_global(dt_iop_module_so_t *module)
Definition borders.c:684
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 borders.c:578
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition borders.c:746
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)
Definition borders.c:369
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)
Definition borders.c:316
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 borders.c:144
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
@ IOP_CS_RGB
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)
@ DT_COLOR_PICKER_POINT
const dt_colormatrix_t dt_aligned_pixel_t out
static const int row
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
#define dt_free_align(ptr)
Definition darktable.h:503
static void * dt_calloc_align(size_t size)
Definition darktable.h:510
#define __OMP_SIMD__(...)
Definition darktable.h:274
@ DT_DEBUG_OPENCL
Definition darktable.h:744
#define dt_gui_freeze_begin()
Definition darktable.h:900
#define dt_gui_freeze_end()
Definition darktable.h:901
#define dt_free(ptr)
Definition darktable.h:478
void void void gboolean dt_gui_widgets_suppressed(void)
Definition gtk.c:194
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define __DT_CLONE_TARGETS__
Definition darktable.h:379
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:270
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition darktable.h:271
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:42
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled, const dt_develop_blend_colorspace_t blend_cst)
#define DT_GUI_MODULE(x)
__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)
Definition imagebuf.c:214
void dt_iop_default_init(dt_iop_module_t *module)
Definition imageop.c:321
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:3220
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:199
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:201
@ IOP_GROUP_EFFECTS
Definition imageop.h:172
#define IOP_GUI_ALLOC(module)
Definition imageop.h:638
@ IOP_TAG_DECORATION
Definition imageop.h:182
@ IOP_TAG_DISTORT
Definition imageop.h:181
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
void *const ovoid
float *const restrict const size_t k
#define PHI
Definition math.h:67
size_t size
Definition mipmap_cache.c:3
float dt_aligned_pixel_t[4]
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2164
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2058
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
Definition opencl.c:2289
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2101
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:2155
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
GtkWidget * dtgtk_reset_label_new(const gchar *text, dt_iop_module_t *module, void *param, int param_size)
Definition resetlabel.c:58
struct _GtkWidget GtkWidget
Definition splash.h:29
dt_aligned_pixel_t flcolor
Definition borders.c:400
dt_aligned_pixel_t bcolor
Definition borders.c:399
struct dt_bauhaus_t * bauhaus
Definition darktable.h:806
struct dt_develop_t * develop
Definition darktable.h:798
struct dt_iop_module_t *void * data
GtkWidget * frame_offset
Definition borders.c:138
GtkWidget * frame_picker
Definition borders.c:140
GtkWidget * border_picker
Definition borders.c:133
GtkWidget * frame_colorpick
Definition borders.c:139
GtkWidget * pos_v_slider
Definition borders.c:131
GtkWidget * aspect_slider
Definition borders.c:126
GtkWidget * aspect_orient
Definition borders.c:127
GtkWidget * pos_h_slider
Definition borders.c:129
GModule *dt_dev_operation_t op
Definition imageop.h:260
dt_iop_global_data_t * data
Definition imageop.h:263
dt_iop_params_t * default_params
Definition imageop.h:344
GtkWidget * widget
Definition imageop.h:374
dt_iop_gui_data_t * gui_data
Definition imageop.h:348
dt_iop_global_data_t * global_data
Definition imageop.h:351
dt_aligned_pixel_t picked_color
Definition imageop.h:309
dt_iop_params_t * params
Definition imageop.h:344
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29