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
323 const float size = fabsf(d->size);
324 if(size == 0) return;
325
327 {
328 // for a constant border be sure to base the computation on the larger border, failing that the border
329 // will have a difference size depending on the orientation.
330
331 if(roi_in->width > roi_in->height || !d->max_border_size)
332 {
333 // this means: relative to width and constant for height as well:
334 roi_out->width = (float)roi_in->width / (1.0f - size);
335 roi_out->height = roi_in->height + roi_out->width - roi_in->width;
336 }
337 else
338 {
339 // this means: relative to height and constant for width as well:
340 roi_out->height = (float)roi_in->height / (1.0f - size);
341 roi_out->width = roi_in->width + roi_out->height - roi_in->height;
342 }
343 }
344 else
345 {
346 float image_aspect = roi_in->width / (float)(roi_in->height);
347 float aspect = (d->aspect == DT_IOP_BORDERS_ASPECT_IMAGE_VALUE) ? image_aspect : d->aspect;
348
349 if(d->aspect_orient == DT_IOP_BORDERS_ASPECT_ORIENTATION_AUTO)
350 aspect = ((image_aspect < 1 && aspect > 1) || (image_aspect > 1 && aspect < 1)) ? 1 / aspect : aspect;
351 else if(d->aspect_orient == DT_IOP_BORDERS_ASPECT_ORIENTATION_LANDSCAPE)
352 aspect = (aspect < 1) ? 1 / aspect : aspect;
353 else if(d->aspect_orient == DT_IOP_BORDERS_ASPECT_ORIENTATION_PORTRAIT)
354 aspect = (aspect > 1) ? 1 / aspect : aspect;
355
356 // min width: constant ratio based on size:
357 roi_out->width = (float)roi_in->width / (1.0f - size);
358 // corresponding height: determined by aspect ratio:
359 roi_out->height = (float)roi_out->width / aspect;
360 // insane settings used?
361 if(roi_out->height < (float)roi_in->height / (1.0f - size))
362 {
363 roi_out->height = (float)roi_in->height / (1.0f - size);
364 roi_out->width = (float)roi_out->height * aspect;
365 }
366 }
367
368 // sanity check.
369 roi_out->width = CLAMP(roi_out->width, 1, 3 * roi_in->width);
370 roi_out->height = CLAMP(roi_out->height, 1, 3 * roi_in->height);
371}
372
373// 2nd pass: which roi would this operation need as input to fill the given output region?
374void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
375 struct dt_dev_pixelpipe_iop_t *piece,
376 const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
377{
379 *roi_in = *roi_out;
380 const int bw = (piece->buf_out.width - piece->buf_in.width) * roi_out->scale;
381 const int bh = (piece->buf_out.height - piece->buf_in.height) * roi_out->scale;
382
383 // don't request outside image (no px for borders)
384 roi_in->x = MAX(roi_out->x - bw * d->pos_h, 0);
385 roi_in->y = MAX(roi_out->y - bh * d->pos_v, 0);
386 // subtract upper left border from dimensions
387 roi_in->width -= MAX(bw * d->pos_h - roi_out->x, 0);
388 roi_in->height -= MAX(bh * d->pos_v - roi_out->y, 0);
389
390 // subtract lower right border from dimensions
391 roi_in->width -= roi_out->scale
392 * MAX((roi_in->x + roi_in->width) / roi_out->scale - (piece->buf_in.width), 0);
393 roi_in->height -= roi_out->scale
394 * MAX((roi_in->y + roi_in->height) / roi_out->scale - (piece->buf_in.height), 0);
395 // don't request nothing or outside roi
396 roi_in->width = MIN(roi_out->scale * piece->buf_in.width, MAX(1, roi_in->width));
397 roi_in->height = MIN(roi_out->scale * piece->buf_in.height, MAX(1, roi_in->height));
398 // FIXME: clamping to 1 leads to a one-pixel visual glitch if the right/bottom border completely fills the
399 // FIXME: viewport, but changing it to 0 breaks all of the tiling_callback functions with a division by zero
400}
401
403{
406 int border_top; // 0..bt is rows of top border outside the frameline
407 int fl_top; //bt..ft is the top frameline
408 int image_top; //ft..it is the top border inside the frameline
409 int border_left; // 0..bl is columns of left border outside the frameline
410 int fl_left; //bl..fl is the left frameline
411 int image_left; //fl..il is the left border inside the frameline
412 int image_right; //il..ir is the actual image area
413 int fl_right; //ir..fr is the right border inside the frameline
414 int border_right; //fr..br is the right frameeline
415 int width; //br..width is the right border outside the frameline
416 int image_bot; //it..ib is the actual image area
417 int fl_bot; //ib..fb is the bottom border inside the frameline
418 int border_bot; //fb..bt is the frameline
419 int height; //bt..height is the bottom border outside the frameline
420 int stride; // width of input roi
421};
422
423// this will be called from inside an OpenMP parallel section, so no need to parallelize further
424static inline void set_pixels(float *buf, const dt_aligned_pixel_t color, const int npixels)
425{
426 for (int i = 0; i < npixels; i++)
427 {
428 __OMP_SIMD__(aligned(buf, color : 16))
429 for (int c = 0; c < 4; c++)
430 {
431 buf[4*i+c] = color[c];
432 }
433 }
434}
435
436// this will be called from inside an OpenMP parallel section, so no need to parallelize further
437static inline void copy_pixels(float *out, const float *const in, const int npixels)
438{
439 for (int i = 0; i < npixels; i++)
440 {
441 __OMP_SIMD__(aligned(in, out : 16))
442 for (int c = 0; c < 4; c++)
443 {
444 out[4*i+c] = in[4*i+c];
445 }
446 }
447}
448
450void copy_image_with_border(float *out, const float *const in, const struct border_positions_t *binfo)
451{
452 const int image_width = binfo->image_right - binfo->image_left;
454 for (size_t row = 0; row < binfo->height; row++)
455 {
456 float *outrow = out + 4 * row * binfo->width;
457 if (row < binfo->border_top || row >= binfo->border_bot)
458 {
459 // top/bottom border outside the frameline: entirely the border color
460 set_pixels(outrow, binfo->bcolor, binfo->width);
461 }
462 else if (row < binfo->fl_top || row >= binfo->fl_bot)
463 {
464 // top/bottom frameline
465 set_pixels(outrow, binfo->bcolor, binfo->border_left);
466 set_pixels(outrow + 4*binfo->border_left, binfo->flcolor, binfo->border_right - binfo->border_left);
467 set_pixels(outrow + 4*binfo->border_right, binfo->bcolor, binfo->width - binfo->border_right);
468 }
469 else if (row < binfo->image_top || row >= binfo->image_bot)
470 {
471 // top/bottom border inside the frameline
472 set_pixels(outrow, binfo->bcolor, binfo->border_left);
473 set_pixels(outrow + 4*binfo->border_left, binfo->flcolor, binfo->fl_left - binfo->border_left);
474 set_pixels(outrow + 4*binfo->fl_left, binfo->bcolor, binfo->fl_right - binfo->fl_left);
475 set_pixels(outrow + 4*binfo->fl_right, binfo->flcolor, binfo->border_right - binfo->fl_right);
476 set_pixels(outrow + 4*binfo->border_right, binfo->bcolor, binfo->width - binfo->border_right);
477 }
478 else
479 {
480 // image area: set left border (w/optional frame line), copy image row, set right border (w/optional frame line)
481 // set outer border
482 set_pixels(outrow, binfo->bcolor, binfo->border_left);
483 if (binfo->image_left > binfo->border_left)
484 {
485 // we have a frameline, so set it and the inner border
486 set_pixels(outrow + 4*binfo->border_left, binfo->flcolor, binfo->fl_left - binfo->border_left);
487 set_pixels(outrow + 4*binfo->fl_left, binfo->bcolor, binfo->image_left - binfo->fl_left);
488 }
489 // copy image row
490 copy_pixels(outrow + 4*binfo->image_left, in + 4 * (row - binfo->image_top) * binfo->stride, image_width);
491 // set right border
492 set_pixels(outrow + 4*binfo->image_right, binfo->bcolor, binfo->fl_right - binfo->image_right);
493 if (binfo->width > binfo->fl_right)
494 {
495 // we have a frameline, so set it and the outer border
496 set_pixels(outrow + 4*binfo->fl_right, binfo->flcolor, binfo->border_right - binfo->fl_right);
497 set_pixels(outrow + 4*binfo->border_right, binfo->bcolor, binfo->width - binfo->border_right);
498 }
499 }
500 }
501
502}
503
504int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid,
505 void *const ovoid)
506{
507 const dt_iop_roi_t *const roi_in = &piece->roi_in;
508 const dt_iop_roi_t *const roi_out = &piece->roi_out;
509 const dt_iop_borders_data_t *const d = (dt_iop_borders_data_t *)piece->data;
510
511 const int border_tot_width = (piece->buf_out.width - piece->buf_in.width) * roi_in->scale;
512 const int border_tot_height = (piece->buf_out.height - piece->buf_in.height) * roi_in->scale;
513 const int border_size_t = border_tot_height * d->pos_v;
514 const int border_size_b = border_tot_height - border_size_t;
515 const int border_size_l = border_tot_width * d->pos_h;
516 const int border_size_r = border_tot_width - border_size_l;
517 const int border_in_x = MAX(border_size_l - roi_out->x, 0);
518 const int border_in_y = MAX(border_size_t - roi_out->y, 0);
519
520 // compute frame line parameters
521 const int border_min_size = MIN(MIN(border_size_t, border_size_b), MIN(border_size_l, border_size_r));
522 const int frame_size = border_min_size * d->frame_size;
523
524 const int b_in_x = CLAMP(border_in_x, 0, roi_out->width - 1);
525 struct border_positions_t binfo =
526 { .bcolor = { d->color[0], d->color[1], d->color[2], 1.0f },
527 .flcolor = { d->frame_color[0], d->frame_color[1], d->frame_color[2], 1.0f },
528 .border_top = border_in_y,
529 .fl_top = border_in_y,
530 .image_top = border_in_y,
531 .border_left = b_in_x,
532 .fl_left = b_in_x,
533 .image_left = b_in_x,
534 .image_right = b_in_x + roi_in->width,
535 .fl_right = roi_out->width,
536 .border_right = roi_out->width,
537 .width = roi_out->width,
538 .image_bot = border_in_y + roi_in->height,
539 .fl_bot = roi_out->height,
540 .border_bot = roi_out->height,
541 .height = roi_out->height,
542 .stride = roi_in->width
543 };
544 if (frame_size > 0)
545 {
546 const int image_lx = border_size_l - roi_out->x;
547 const int image_ty = border_size_t - roi_out->y;
548 const int frame_space = border_min_size - frame_size;
549 const int frame_offset = frame_space * d->frame_offset;
550 const int frame_tl_in_x = MAX(border_in_x - frame_offset, 0);
551 const int frame_tl_out_x = MAX(frame_tl_in_x - frame_size, 0);
552 const int frame_tl_in_y = MAX(border_in_y - frame_offset, 0);
553 const int frame_tl_out_y = MAX(frame_tl_in_y - frame_size, 0);
554 binfo.border_top = frame_tl_out_y;
555 binfo.fl_top = frame_tl_in_y;
556 binfo.border_left = CLAMP(frame_tl_out_x, 0, roi_out->width);
557 binfo.fl_left = CLAMP(frame_tl_in_x, 0, roi_out->width);
558 const int frame_in_width = floor((piece->buf_in.width * roi_in->scale) + frame_offset * 2);
559 const int frame_in_height = floor((piece->buf_in.height * roi_in->scale) + frame_offset * 2);
560 const int frame_out_width = frame_in_width + frame_size * 2;
561 const int frame_out_height = frame_in_height + frame_size * 2;
562 const int frame_br_in_x = CLAMP(image_lx - frame_offset + frame_in_width - 1, 0, roi_out->width - 1);
563 const int frame_br_in_y = CLAMP(image_ty - frame_offset + frame_in_height - 1, 0, roi_out->height - 1);
564 // ... if 100% frame_offset we ensure frame_line "stick" the out border
565 const int frame_br_out_x
566 = (d->frame_offset == 1.0f && (border_min_size == MIN(border_size_l, border_size_r)))
567 ? (roi_out->width)
568 : CLAMP(image_lx - frame_offset - frame_size + frame_out_width - 1, 0, roi_out->width - 1);
569 const int frame_br_out_y
570 = (d->frame_offset == 1.0f && (border_min_size == MIN(border_size_t, border_size_b)))
571 ? (roi_out->height)
572 : CLAMP(image_ty - frame_offset - frame_size + frame_out_height - 1, 0, roi_out->height - 1);
573 binfo.fl_right = frame_br_in_x + 1; // need end+1 for these coordinates
574 binfo.border_right = frame_br_out_x + 1;
575 binfo.fl_bot = frame_br_in_y + 1;
576 binfo.border_bot = frame_br_out_y + 1;
577 }
578 copy_image_with_border((float*)ovoid, (const float*)ivoid, &binfo);
579 return 0;
580}
581
582#ifdef HAVE_OPENCL
583int 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)
584{
585 const dt_iop_roi_t *const roi_in = &piece->roi_in;
586 const dt_iop_roi_t *const roi_out = &piece->roi_out;
589
590 cl_int err = -999;
591 const int devid = pipe->devid;
592
593 const int width = roi_out->width;
594 const int height = roi_out->height;
595
596 const int border_tot_width = (piece->buf_out.width - piece->buf_in.width) * roi_in->scale;
597 const int border_tot_height = (piece->buf_out.height - piece->buf_in.height) * roi_in->scale;
598 const int border_size_t = border_tot_height * d->pos_v;
599 const int border_size_b = border_tot_height - border_size_t;
600 const int border_size_l = border_tot_width * d->pos_h;
601 const int border_size_r = border_tot_width - border_size_l;
602 const int border_in_x = MAX(border_size_l - roi_out->x, 0);
603 const int border_in_y = MAX(border_size_t - roi_out->y, 0);
604
605 // ----- Filling border
606 const float col[4] = { d->color[0], d->color[1], d->color[2], 1.0f };
607 size_t sizes[2] = { ROUNDUPDWD(width, devid), ROUNDUPDHT(height, devid) };
608 const int zero = 0;
609 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 0, sizeof(cl_mem), &dev_out);
610 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 1, sizeof(int), &zero);
611 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 2, sizeof(int), &zero);
612 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 3, sizeof(int), &width);
613 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 4, sizeof(int), &height);
614 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 5, 4 * sizeof(float), &col);
615 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_borders_fill, sizes);
616 if(err != CL_SUCCESS) goto error;
617
618 // ----- Frame line
619 const int border_min_size = MIN(MIN(border_size_t, border_size_b), MIN(border_size_l, border_size_r));
620 const int frame_size = border_min_size * d->frame_size;
621 if(frame_size != 0)
622 {
623 const float col_frame[4] = { d->frame_color[0], d->frame_color[1], d->frame_color[2], 1.0f };
624 const int image_lx = border_size_l - roi_out->x;
625 const int image_ty = border_size_t - roi_out->y;
626 const int frame_space = border_min_size - frame_size;
627 const int frame_offset = frame_space * d->frame_offset;
628 const int frame_tl_in_x = MAX(border_in_x - frame_offset, 0);
629 const int frame_tl_out_x = MAX(frame_tl_in_x - frame_size, 0);
630 const int frame_tl_in_y = MAX(border_in_y - frame_offset, 0);
631 const int frame_tl_out_y = MAX(frame_tl_in_y - frame_size, 0);
632 const int frame_in_width = floor((piece->buf_in.width * roi_in->scale) + frame_offset * 2);
633 const int frame_in_height = floor((piece->buf_in.height * roi_in->scale) + frame_offset * 2);
634 const int frame_out_width = frame_in_width + frame_size * 2;
635 const int frame_out_height = frame_in_height + frame_size * 2;
636 const int frame_br_in_x = CLAMP(image_lx - frame_offset + frame_in_width - 1, 0, roi_out->width - 1);
637 const int frame_br_in_y = CLAMP(image_ty - frame_offset + frame_in_height - 1, 0, roi_out->height - 1);
638 // ... if 100% frame_offset we ensure frame_line "stick" the out border
639 const int frame_br_out_x
640 = (d->frame_offset == 1.0f && (border_min_size == MIN(border_size_l, border_size_r)))
641 ? (roi_out->width)
642 : CLAMP(image_lx - frame_offset - frame_size + frame_out_width - 1, 0, roi_out->width);
643 const int frame_br_out_y
644 = (d->frame_offset == 1.0f && (border_min_size == MIN(border_size_t, border_size_b)))
645 ? (roi_out->height)
646 : CLAMP(image_ty - frame_offset - frame_size + frame_out_height - 1, 0, roi_out->height);
647
648 const int roi_frame_in_width = frame_br_in_x - frame_tl_in_x;
649 const int roi_frame_in_height = frame_br_in_y - frame_tl_in_y;
650 const int roi_frame_out_width = frame_br_out_x - frame_tl_out_x;
651 const int roi_frame_out_height = frame_br_out_y - frame_tl_out_y;
652
653 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 0, sizeof(cl_mem), &dev_out);
654 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 1, sizeof(int), &frame_tl_out_x);
655 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 2, sizeof(int), &frame_tl_out_y);
656 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 3, sizeof(int), &roi_frame_out_width);
657 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 4, sizeof(int), &roi_frame_out_height);
658 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 5, 4 * sizeof(float), &col_frame);
659 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_borders_fill, sizes);
660 if(err != CL_SUCCESS) goto error;
661
662 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 0, sizeof(cl_mem), &dev_out);
663 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 1, sizeof(int), &frame_tl_in_x);
664 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 2, sizeof(int), &frame_tl_in_y);
665 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 3, sizeof(int), &roi_frame_in_width);
666 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 4, sizeof(int), &roi_frame_in_height);
667 dt_opencl_set_kernel_arg(devid, gd->kernel_borders_fill, 5, 4 * sizeof(float), &col);
668 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_borders_fill, sizes);
669 if(err != CL_SUCCESS) goto error;
670 }
671
672 size_t iorigin[] = { 0, 0, 0 };
673 size_t oorigin[] = { border_in_x, border_in_y, 0 };
674 size_t region[] = { roi_in->width, roi_in->height, 1 };
675
676 // copy original input from dev_in -> dev_out as starting point
677 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, iorigin, oorigin, region);
678 if(err != CL_SUCCESS) goto error;
679
680 return TRUE;
681
682error:
683 dt_print(DT_DEBUG_OPENCL, "[opencl_borders] couldn't enqueue kernel! %d\n", err);
684 return FALSE;
685}
686#endif
687
688
690{
691 const int program = 2; // basic.cl from programs.conf
694 module->data = gd;
695 gd->kernel_borders_fill = dt_opencl_create_kernel(program, "borders_fill");
696}
697
698
705
706
714
716{
718 piece->data_size = sizeof(dt_iop_borders_data_t);
719}
720
722{
723 dt_free_align(piece->data);
724 piece->data = NULL;
725}
726
728{
729 dt_iop_borders_params_t p = (dt_iop_borders_params_t){ { 1.0f, 1.0f, 1.0f },
730 3.0f / 2.0f,
731 "3:2",
732 0,
733 0.1f,
734 0.5f,
735 "1/2",
736 0.5f,
737 "1/2",
738 0.0f,
739 0.5f,
740 { 0.0f, 0.0f, 0.0f },
741 TRUE };
742 dt_gui_presets_add_generic(_("15:10 postcard white"), self->op,
743 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_NONE);
744
745 p.color[0] = p.color[1] = p.color[2] = 0.0f;
746 p.frame_color[0] = p.frame_color[1] = p.frame_color[2] = 1.0f;
747 dt_gui_presets_add_generic(_("15:10 postcard black"), self->op,
748 self->version(), &p, sizeof(p), 1, DEVELOP_BLEND_CS_NONE);
749}
750
752{
755
756 if(fabsf(p->color[0] - self->picked_color[0]) < 0.0001f
757 && fabsf(p->color[1] - self->picked_color[1]) < 0.0001f
758 && fabsf(p->color[2] - self->picked_color[2]) < 0.0001f)
759 {
760 // interrupt infinite loops
761 return;
762 }
763
764 if(fabsf(p->frame_color[0] - self->picked_color[0]) < 0.0001f
765 && fabsf(p->frame_color[1] - self->picked_color[1]) < 0.0001f
766 && fabsf(p->frame_color[2] - self->picked_color[2]) < 0.0001f)
767 {
768 // interrupt infinite loops
769 return;
770 }
771
772 GdkRGBA c = (GdkRGBA){.red = self->picked_color[0],
773 .green = self->picked_color[1],
774 .blue = self->picked_color[2],
775 .alpha = 1.0 };
776
777 if(picker == g->frame_picker)
778 {
779 p->frame_color[0] = self->picked_color[0];
780 p->frame_color[1] = self->picked_color[1];
781 p->frame_color[2] = self->picked_color[2];
782 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->frame_colorpick), &c);
783 }
784 else if(picker == g->border_picker)
785 {
786 p->color[0] = self->picked_color[0];
787 p->color[1] = self->picked_color[1];
788 p->color[2] = self->picked_color[2];
789 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->colorpick), &c);
790 }
791
793}
794
795static void aspect_changed(GtkWidget *combo, dt_iop_module_t *self)
796{
799 const int which = dt_bauhaus_combobox_get(combo);
800 const char *text = dt_bauhaus_combobox_get_text(combo);
801 if(which == dt_bauhaus_combobox_length(combo)-1)
802 {
803 g_strlcpy(p->aspect_text, text, sizeof(p->aspect_text));
804 }
805 else if(which < DT_IOP_BORDERS_ASPECT_COUNT)
806 {
807 g_strlcpy(p->aspect_text, text, sizeof(p->aspect_text));
808 p->aspect = g->aspect_ratios[which];
810 dt_bauhaus_slider_set(g->aspect_slider,p->aspect);
812 }
815}
816
818{
821 const int which = dt_bauhaus_combobox_get(combo);
822 const char *text = dt_bauhaus_combobox_get_text(combo);
823 if(which == dt_bauhaus_combobox_length(combo)-1)
824 {
825 g_strlcpy(p->aspect_text, text, sizeof(p->aspect_text));
826 }
827 else if(which < DT_IOP_BORDERS_POSITION_H_COUNT)
828 {
829 g_strlcpy(p->pos_h_text, text, sizeof(p->pos_h_text));
830 p->pos_h = g->pos_h_ratios[which];
832 dt_bauhaus_slider_set(g->pos_h_slider,p->pos_h);
834 }
837}
838
840{
843 const int which = dt_bauhaus_combobox_get(combo);
844 const char *text = dt_bauhaus_combobox_get_text(combo);
845 if(which == dt_bauhaus_combobox_length(combo)-1)
846 {
847 g_strlcpy(p->aspect_text, text, sizeof(p->aspect_text));
848 }
849 else if(which < DT_IOP_BORDERS_POSITION_V_COUNT)
850 {
851 g_strlcpy(p->pos_v_text, text, sizeof(p->pos_v_text));
852 p->pos_v = g->pos_v_ratios[which];
854 dt_bauhaus_slider_set(g->pos_v_slider,p->pos_v);
856 }
859}
860
861void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
862{
864
865 if (w == g->aspect_slider)
866 {
868 }
869 else if(w == g->pos_h_slider)
870 {
872 }
873 else if(w == g->pos_v_slider)
874 {
876 }
877}
878
879static void colorpick_color_set(GtkColorButton *widget, dt_iop_module_t *self)
880{
881 if(darktable.gui->reset) return;
883
884 // turn off the other color picker so that this tool actually works ...
886
887 GdkRGBA c;
888 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &c);
889 p->color[0] = c.red;
890 p->color[1] = c.green;
891 p->color[2] = c.blue;
892
894}
895
896
897static void frame_colorpick_color_set(GtkColorButton *widget, dt_iop_module_t *self)
898{
899 if(darktable.gui->reset) return;
901
902 // turn off the other color picker so that this tool actually works ...
904
905 GdkRGBA c;
906 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &c);
907 p->frame_color[0] = c.red;
908 p->frame_color[1] = c.green;
909 p->frame_color[2] = c.blue;
910
912}
913
914void gui_update(struct dt_iop_module_t *self)
915{
918
919// FIXME by hand
920 // ----- Aspect
921 int k = 0;
923 {
924 if(fabsf(p->aspect - g->aspect_ratios[k]) < 0.01f)
925 {
926 dt_bauhaus_combobox_set(g->aspect, k);
927 break;
928 }
929 }
931 {
932 dt_bauhaus_combobox_set(g->aspect, k);
933 }
934
935 // ----- Position H
936 for(k = 0; k < DT_IOP_BORDERS_POSITION_H_COUNT; k++)
937 {
938 if(fabsf(p->pos_h - g->pos_h_ratios[k]) < 0.01f)
939 {
940 dt_bauhaus_combobox_set(g->pos_h, k);
941 break;
942 }
943 }
945 {
946 dt_bauhaus_combobox_set(g->pos_h, k);
947 }
948
949 // ----- Position V
950 for(k = 0; k < DT_IOP_BORDERS_POSITION_V_COUNT; k++)
951 {
952 if(fabsf(p->pos_v - g->pos_v_ratios[k]) < 0.01f)
953 {
954 dt_bauhaus_combobox_set(g->pos_v, k);
955 break;
956 }
957 }
959 {
960 dt_bauhaus_combobox_set(g->pos_v, k);
961 }
962
963 // ----- Border Color
964 GdkRGBA c = (GdkRGBA){.red = p->color[0], .green = p->color[1], .blue = p->color[2], .alpha = 1.0 };
965 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->colorpick), &c);
966
967 // ----- Frame Color
968 GdkRGBA fc = (GdkRGBA){
969 .red = p->frame_color[0], .green = p->frame_color[1], .blue = p->frame_color[2], .alpha = 1.0
970 };
971 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(g->frame_colorpick), &fc);
972}
973
974static void gui_init_aspect(struct dt_iop_module_t *self)
975{
977
978 dt_bauhaus_combobox_add(g->aspect, _("image"));
979 dt_bauhaus_combobox_add(g->aspect, _("3:1"));
980 dt_bauhaus_combobox_add(g->aspect, _("95:33"));
981 dt_bauhaus_combobox_add(g->aspect, _("2:1"));
982 dt_bauhaus_combobox_add(g->aspect, _("16:9"));
983 dt_bauhaus_combobox_add(g->aspect, _("golden cut"));
984 dt_bauhaus_combobox_add(g->aspect, _("3:2"));
985 dt_bauhaus_combobox_add(g->aspect, _("A4"));
986 dt_bauhaus_combobox_add(g->aspect, _("DIN"));
987 dt_bauhaus_combobox_add(g->aspect, _("4:3"));
988 dt_bauhaus_combobox_add(g->aspect, _("square"));
989 dt_bauhaus_combobox_add(g->aspect, _("constant border"));
990 dt_bauhaus_combobox_add(g->aspect, _("custom..."));
991
994 int i = 1;
995 g->aspect_ratios[i++] = 3.0f;
996 g->aspect_ratios[i++] = 95.0f / 33.0f;
997 g->aspect_ratios[i++] = 2.0f;
998 g->aspect_ratios[i++] = 16.0f / 9.0f;
999 g->aspect_ratios[i++] = PHI;
1000 g->aspect_ratios[i++] = 3.0f / 2.0f;
1001 g->aspect_ratios[i++] = 297.0f / 210.0f;
1002 g->aspect_ratios[i++] = sqrtf(2.0f);
1003 g->aspect_ratios[i++] = 4.0f / 3.0f;
1004 g->aspect_ratios[i++] = 1.0f;
1005}
1006
1007static void gui_init_positions(struct dt_iop_module_t *self)
1008{
1010
1011 dt_bauhaus_combobox_add(g->pos_h, _("center"));
1012 dt_bauhaus_combobox_add(g->pos_h, _("1/3"));
1013 dt_bauhaus_combobox_add(g->pos_h, _("3/8"));
1014 dt_bauhaus_combobox_add(g->pos_h, _("5/8"));
1015 dt_bauhaus_combobox_add(g->pos_h, _("2/3"));
1016 dt_bauhaus_combobox_add(g->pos_h, _("custom..."));
1017 dt_bauhaus_combobox_add(g->pos_v, _("center"));
1018 dt_bauhaus_combobox_add(g->pos_v, _("1/3"));
1019 dt_bauhaus_combobox_add(g->pos_v, _("3/8"));
1020 dt_bauhaus_combobox_add(g->pos_v, _("5/8"));
1021 dt_bauhaus_combobox_add(g->pos_v, _("2/3"));
1022 dt_bauhaus_combobox_add(g->pos_v, _("custom..."));
1023
1024 int i = 0;
1025 g->pos_h_ratios[i++] = 0.5f;
1026 g->pos_h_ratios[i++] = 1.0f / 3.0f;
1027 g->pos_h_ratios[i++] = 3.0f / 8.0f;
1028 g->pos_h_ratios[i++] = 5.0f / 8.0f;
1029 g->pos_h_ratios[i++] = 2.0f / 3.0f;
1030 i = 0;
1031 g->pos_v_ratios[i++] = 0.5f;
1032 g->pos_v_ratios[i++] = 1.0f / 3.0f;
1033 g->pos_v_ratios[i++] = 3.0f / 8.0f;
1034 g->pos_v_ratios[i++] = 5.0f / 8.0f;
1035 g->pos_v_ratios[i++] = 2.0f / 3.0f;
1036}
1037
1038void gui_init(struct dt_iop_module_t *self)
1039{
1042
1043 g->size = dt_bauhaus_slider_from_params(self, "size");
1045 dt_bauhaus_slider_set_format(g->size, "%");
1046 gtk_widget_set_tooltip_text(g->size, _("size of the border in percent of the full image"));
1047
1050 dt_bauhaus_widget_set_label(g->aspect, N_("aspect"));
1051 gtk_box_pack_start(GTK_BOX(self->widget), g->aspect, TRUE, TRUE, 0);
1052 gui_init_aspect(self);
1053 g_signal_connect(G_OBJECT(g->aspect), "value-changed", G_CALLBACK(aspect_changed), self);
1054 gtk_widget_set_tooltip_text(g->aspect, _("select the aspect ratio or right click and type your own (w:h)"));
1055 g->aspect_slider = dt_bauhaus_slider_from_params(self, "aspect");
1056 gtk_widget_set_tooltip_text(g->aspect_slider, _("set the custom aspect ratio"));
1057
1058 g->aspect_orient = dt_bauhaus_combobox_from_params(self, "aspect_orient");
1059 dt_bauhaus_combobox_add(g->aspect_orient, _("auto"));
1060 dt_bauhaus_combobox_add(g->aspect_orient, _("portrait"));
1061 dt_bauhaus_combobox_add(g->aspect_orient, _("landscape"));
1062 gtk_widget_set_tooltip_text(g->aspect_orient, _("aspect ratio orientation of the image with border"));
1063
1066 dt_bauhaus_widget_set_label(g->pos_h, N_("horizontal position"));
1067 gtk_box_pack_start(GTK_BOX(self->widget), g->pos_h, TRUE, TRUE, 0);
1068 g_signal_connect(G_OBJECT(g->pos_h), "value-changed", G_CALLBACK(position_h_changed), self);
1069 gtk_widget_set_tooltip_text(g->pos_h, _("select the horizontal position ratio relative to top "
1070 "or right click and type your own (y:h)"));
1071 g->pos_h_slider = dt_bauhaus_slider_from_params(self, "pos_h");
1072 gtk_widget_set_tooltip_text(g->pos_h_slider, _("custom horizontal position"));
1073
1076 dt_bauhaus_widget_set_label(g->pos_v, N_("vertical position"));
1077 gtk_box_pack_start(GTK_BOX(self->widget), g->pos_v, TRUE, TRUE, 0);
1078 g_signal_connect(G_OBJECT(g->pos_v), "value-changed", G_CALLBACK(position_v_changed), self);
1079 gtk_widget_set_tooltip_text(g->pos_v, _("select the vertical position ratio relative to left "
1080 "or right click and type your own (x:w)"));
1081 g->pos_v_slider = dt_bauhaus_slider_from_params(self, "pos_v");
1082 gtk_widget_set_tooltip_text(g->pos_v_slider, _("custom vertical position"));
1083
1084 gui_init_positions(self);
1085
1086 g->frame_size = dt_bauhaus_slider_from_params(self, "frame_size");
1087 dt_bauhaus_slider_set_digits(g->frame_size, 4);
1088 dt_bauhaus_slider_set_format(g->frame_size, "%");
1089 gtk_widget_set_tooltip_text(g->frame_size, _("size of the frame line in percent of min border width"));
1090
1091 g->frame_offset = dt_bauhaus_slider_from_params(self, "frame_offset");
1092 dt_bauhaus_slider_set_digits(g->frame_offset, 4);
1093 dt_bauhaus_slider_set_format(g->frame_offset, "%");
1094 gtk_widget_set_tooltip_text(g->frame_offset, _("offset of the frame line beginning on picture side"));
1095
1096 GdkRGBA color = (GdkRGBA){.red = p->color[0], .green = p->color[1], .blue = p->color[2], .alpha = 1.0 };
1097
1098 GtkWidget *label, *box;
1099
1100 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1101 label = dtgtk_reset_label_new(_("border color"), self, &p->color, 3 * sizeof(float));
1102 gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
1103 g->colorpick = gtk_color_button_new_with_rgba(&color);
1104 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(g->colorpick), FALSE);
1105 gtk_color_button_set_title(GTK_COLOR_BUTTON(g->colorpick), _("select border color"));
1106 g_signal_connect(G_OBJECT(g->colorpick), "color-set", G_CALLBACK(colorpick_color_set), self);
1107 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(g->colorpick), FALSE, TRUE, 0);
1108 g->border_picker = dt_color_picker_new(self, DT_COLOR_PICKER_POINT, box);
1109 gtk_widget_set_tooltip_text(GTK_WIDGET(g->border_picker), _("pick border color from image"));
1110 gtk_box_pack_start(GTK_BOX(self->widget), box, TRUE, TRUE, 0);
1111
1112 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
1113 label = dtgtk_reset_label_new(_("frame line color"), self, &p->color, 3 * sizeof(float));
1114 gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
1115 g->frame_colorpick = gtk_color_button_new_with_rgba(&color);
1116 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(g->frame_colorpick), FALSE);
1117 gtk_color_button_set_title(GTK_COLOR_BUTTON(g->frame_colorpick), _("select frame line color"));
1118 g_signal_connect(G_OBJECT(g->frame_colorpick), "color-set", G_CALLBACK(frame_colorpick_color_set), self);
1119 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(g->frame_colorpick), FALSE, TRUE, 0);
1120 g->frame_picker = dt_color_picker_new(self, DT_COLOR_PICKER_POINT, box);
1121 gtk_widget_set_tooltip_text(GTK_WIDGET(g->frame_picker), _("pick frame line color from image"));
1122 gtk_box_pack_start(GTK_BOX(self->widget), box, TRUE, TRUE, 0);
1123}
1124
1125
1127{
1128 dt_iop_default_init(self);
1129
1130 dt_iop_borders_params_t *defaults = self->default_params;
1131
1132 g_strlcpy(defaults->aspect_text, "constant border", sizeof(defaults->aspect_text));
1133 g_strlcpy(defaults->pos_h_text, "1/2", sizeof(defaults->pos_h_text));
1134 g_strlcpy(defaults->pos_v_text, "1/2", sizeof(defaults->pos_v_text));
1135}
1136
1137// clang-format off
1138// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1139// vim: shiftwidth=2 expandtab tabstop=2 cindent
1140// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1141// 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:3534
void dt_bauhaus_combobox_set_editable(GtkWidget *widget, int editable)
Definition bauhaus.c:2074
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2347
int dt_bauhaus_combobox_length(GtkWidget *widget)
Definition bauhaus.c:2155
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
Definition bauhaus.c:2162
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2301
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1653
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1842
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3598
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
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:839
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:707
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:1007
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:879
#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:715
static void position_h_changed(GtkWidget *combo, dt_iop_module_t *self)
Definition borders.c:817
const char * name()
Definition borders.c:209
void gui_update(struct dt_iop_module_t *self)
Definition borders.c:914
static void gui_init_aspect(struct dt_iop_module_t *self)
Definition borders.c:974
static void aspect_changed(GtkWidget *combo, dt_iop_module_t *self)
Definition borders.c:795
void gui_init(struct dt_iop_module_t *self)
Definition borders.c:1038
__DT_CLONE_TARGETS__ void copy_image_with_border(float *out, const float *const in, const struct border_positions_t *binfo)
Definition borders.c:450
#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:861
void cleanup_global(dt_iop_module_so_t *module)
Definition borders.c:699
static void set_pixels(float *buf, const dt_aligned_pixel_t color, const int npixels)
Definition borders.c:424
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:437
void init_presets(dt_iop_module_so_t *self)
Definition borders.c:727
static void frame_colorpick_color_set(GtkColorButton *widget, dt_iop_module_t *self)
Definition borders.c:897
void init(dt_iop_module_t *self)
Definition borders.c:1126
#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:504
#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:721
void init_global(dt_iop_module_so_t *module)
Definition borders.c:689
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:583
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:751
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:374
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:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
#define __OMP_SIMD__(...)
Definition darktable.h:262
@ DT_DEBUG_OPENCL
Definition darktable.h:722
#define dt_free(ptr)
Definition darktable.h:456
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition darktable.h:259
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:41
#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:316
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:3141
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:169
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:171
@ IOP_GROUP_EFFECTS
Definition imageop.h:142
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
@ IOP_TAG_DECORATION
Definition imageop.h:152
@ IOP_TAG_DISTORT
Definition imageop.h:151
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:2136
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2030
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:2261
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2073
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:2127
#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:405
dt_aligned_pixel_t bcolor
Definition borders.c:404
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_develop_t * develop
Definition darktable.h:770
struct dt_iop_module_t *void * data
int32_t reset
Definition gtk.h:172
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:230
dt_iop_global_data_t * data
Definition imageop.h:233
dt_iop_params_t * default_params
Definition imageop.h:307
GtkWidget * widget
Definition imageop.h:337
dt_iop_gui_data_t * gui_data
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:314
dt_aligned_pixel_t picked_color
Definition imageop.h:272
dt_iop_params_t * params
Definition imageop.h:307
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