Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
lens.cc
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2013, 2016 johannes hanika.
4 Copyright (C) 2010 Alexandre Prokoudine.
5 Copyright (C) 2010-2011 Bruce Guenter.
6 Copyright (C) 2010-2011, 2013 Henrik Andersson.
7 Copyright (C) 2010 Milan Knížek.
8 Copyright (C) 2010, 2013-2014 Pascal de Bruijn.
9 Copyright (C) 2010 Stuart Henderson.
10 Copyright (C) 2010 Thierry Leconte.
11 Copyright (C) 2011, 2013 Antony Dovgal.
12 Copyright (C) 2011-2012 Jérémy Rosen.
13 Copyright (C) 2011 Olivier Tribout.
14 Copyright (C) 2011 Robert Bieber.
15 Copyright (C) 2011 Rostyslav Pidgornyi.
16 Copyright (C) 2011-2014, 2016-2019 Tobias Ellinghaus.
17 Copyright (C) 2012 Edouard Gomez.
18 Copyright (C) 2012-2013 Gabriel Ebner.
19 Copyright (C) 2012, 2015, 2019 parafin.
20 Copyright (C) 2012 Richard Wonka.
21 Copyright (C) 2012 Sergey Pavlov.
22 Copyright (C) 2012-2014, 2016-2017 Ulrich Pegelow.
23 Copyright (C) 2013, 2020-2021 Aldric Renaudin.
24 Copyright (C) 2013 Guilherme Brondani Torri.
25 Copyright (C) 2013 Ivan Tarozzi.
26 Copyright (C) 2013-2016 Roman Lebedev.
27 Copyright (C) 2013 Simon Spannagel.
28 Copyright (C) 2013 Thomas Pryds.
29 Copyright (C) 2013-2015 Torsten Bronger.
30 Copyright (C) 2015 Pedro Côrte-Real.
31 Copyright (C) 2016, 2018-2022 Pascal Obry.
32 Copyright (C) 2017 Heiko Bauke.
33 Copyright (C) 2018-2026 Aurélien PIERRE.
34 Copyright (C) 2018 Edgardo Hoszowski.
35 Copyright (C) 2018 Kelvie Wong.
36 Copyright (C) 2018 Maurizio Paglia.
37 Copyright (C) 2018 Peter Budai.
38 Copyright (C) 2018, 2021 rawfiner.
39 Copyright (C) 2019 Andreas Schneider.
40 Copyright (C) 2019 David-Tillmann Schaefer.
41 Copyright (C) 2019 Diederik ter Rahe.
42 Copyright (C) 2019 Jakub Filipowicz.
43 Copyright (C) 2019 Kevin Daudt.
44 Copyright (C) 2020-2021 Chris Elston.
45 Copyright (C) 2020-2022 Diederik Ter Rahe.
46 Copyright (C) 2020-2022 Hanno Schwalm.
47 Copyright (C) 2020 Hubert Kowalski.
48 Copyright (C) 2020-2021 Ralf Brown.
49 Copyright (C) 2021 fvollmer.
50 Copyright (C) 2022 Martin Bařinka.
51 Copyright (C) 2022 Nicolas Auffray.
52 Copyright (C) 2022 Philipp Lutz.
53 Copyright (C) 2024-2025 Alynx Zhou.
54
55 darktable is free software: you can redistribute it and/or modify
56 it under the terms of the GNU General Public License as published by
57 the Free Software Foundation, either version 3 of the License, or
58 (at your option) any later version.
59
60 darktable is distributed in the hope that it will be useful,
61 but WITHOUT ANY WARRANTY; without even the implied warranty of
62 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63 GNU General Public License for more details.
64
65 You should have received a copy of the GNU General Public License
66 along with darktable. If not, see <http://www.gnu.org/licenses/>.
67*/
68#include "common/darktable.h"
69#include "glib.h"
70
71#ifdef HAVE_CONFIG_H
72#include "config.h"
73#endif
74#include "bauhaus/bauhaus.h"
77#include "common/imagebuf.h"
78#include "common/opencl.h"
79#include "control/control.h"
80#include "develop/develop.h"
81#include "develop/imageop.h"
82#include "develop/imageop_gui.h"
83#include "develop/tiling.h"
84#include "dtgtk/button.h"
85#include "dtgtk/resetlabel.h"
86
87#include "gui/draw.h"
88#include "gui/gtk.h"
89#include "iop/iop_api.h"
90#include <assert.h>
91#include <ctype.h>
92#include <gtk/gtk.h>
93#include <inttypes.h>
94#include <math.h>
95#include <stdlib.h>
96#include <string.h>
97
98#include <lensfun.h>
99
100extern "C" {
101
102#if LF_VERSION < ((0 << 24) | (2 << 16) | (9 << 8) | 0)
103#define LF_SEARCH_SORT_AND_UNIQUIFY 2
104#endif
105
106#if LF_VERSION == ((0 << 24) | (3 << 16) | (95 << 8) | 0)
107#define LF_0395
108#endif
109
111
113{
115 LENSFUN_MODFLAG_ALL = LF_MODIFY_DISTORTION | LF_MODIFY_TCA | LF_MODIFY_VIGNETTING,
116 LENSFUN_MODFLAG_DIST_TCA = LF_MODIFY_DISTORTION | LF_MODIFY_TCA,
117 LENSFUN_MODFLAG_DIST_VIGN = LF_MODIFY_DISTORTION | LF_MODIFY_VIGNETTING,
118 LENSFUN_MODFLAG_TCA_VIGN = LF_MODIFY_TCA | LF_MODIFY_VIGNETTING,
119 LENSFUN_MODFLAG_DIST = LF_MODIFY_DISTORTION,
120 LENSFUN_MODFLAG_TCA = LF_MODIFY_TCA,
121 LENSFUN_MODFLAG_VIGN = LF_MODIFY_VIGNETTING,
122 LENSFUN_MODFLAG_MASK = LF_MODIFY_DISTORTION | LF_MODIFY_TCA | LF_MODIFY_VIGNETTING
124
126{
127 char name[80];
128 int pos; // position in combo box
131
133{
135 int inverse; // $MIN: 0 $MAX: 1 $DEFAULT: 0 $DESCRIPTION: "mode"
136 float scale; // $MIN: 0.1 $MAX: 2.0 $DEFAULT: 1.0
137 float crop;
138 float focal;
139 float aperture;
140 float distance;
141 lfLensType target_geom; // $DEFAULT: LF_RECTILINEAR $DESCRIPTION: "geometry"
142 char camera[128];
143 char lens[128];
144 gboolean tca_override; // $DEFAULT: FALSE $DESCRIPTION: "TCA overwrite"
145 float tca_r; // $MIN: 0.99 $MAX: 1.01 $DEFAULT: 1.0 $DESCRIPTION: "TCA red"
146 float tca_b; // $MIN: 0.99 $MAX: 1.01 $DEFAULT: 1.0 $DESCRIPTION: "TCA blue"
147 int modified; // $DEFAULT: 0 did user changed anything from automatically detected?
149
167
176
178{
179 lfLens *lens;
182 float scale;
183 float crop;
184 float focal;
185 float aperture;
186 float distance;
187 lfLensType target_geom;
189 gboolean tca_override;
190 lfLensCalibTCA custom_tca;
192
193
194const char *name()
195{
196 return _("_lens correction");
197}
198
199const char *aliases()
200{
201 return _("vignette|chromatic aberrations|distortion");
202}
203
204const char **description(struct dt_iop_module_t *self)
205{
206 return dt_iop_set_description(self, _("correct lenses optical flaws"),
207 _("corrective"),
208 _("linear, RGB, scene-referred"),
209 _("geometric and reconstruction, RGB"),
210 _("linear, RGB, scene-referred"));
211}
212
213
215{
216 return IOP_GROUP_REPAIR;
217}
218
220{
221 return IOP_TAG_DISTORT;
222}
223
228
230{
231 return IOP_CS_RGB;
232}
233
234int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
235 void *new_params, const int new_version)
236{
237 if(old_version == 2 && new_version == 5)
238 {
239 // legacy params of version 2; version 1 comes from ancient times and seems to be forgotten by now
240 typedef struct
241 {
242 int modify_flags;
243 int inverse;
244 float scale;
245 float crop;
246 float focal;
247 float aperture;
248 float distance;
249 lfLensType target_geom;
250 char camera[52];
251 char lens[52];
252 int tca_override;
253 float tca_r, tca_b;
254 } dt_iop_lensfun_params_v2_t;
255
256 const dt_iop_lensfun_params_v2_t *o = (dt_iop_lensfun_params_v2_t *)old_params;
259
260 *n = *d; // start with a fresh copy of default parameters
261
262 n->modify_flags = o->modify_flags;
263 n->inverse = o->inverse;
264 n->scale = o->scale;
265 n->crop = o->crop;
266 n->focal = o->focal;
267 n->aperture = o->aperture;
268 n->distance = o->distance;
269 n->target_geom = o->target_geom;
270 n->tca_override = o->tca_override;
271 g_strlcpy(n->camera, o->camera, sizeof(n->camera));
272 g_strlcpy(n->lens, o->lens, sizeof(n->lens));
273 n->modified = 1;
274
275 // old versions had R and B swapped
276 n->tca_r = o->tca_b;
277 n->tca_b = o->tca_r;
278
279 return 0;
280 }
281 if(old_version == 3 && new_version == 5)
282 {
283 typedef struct
284 {
285 int modify_flags;
286 int inverse;
287 float scale;
288 float crop;
289 float focal;
290 float aperture;
291 float distance;
292 lfLensType target_geom;
293 char camera[128];
294 char lens[128];
295 int tca_override;
296 float tca_r, tca_b;
297 } dt_iop_lensfun_params_v3_t;
298
299 const dt_iop_lensfun_params_v3_t *o = (dt_iop_lensfun_params_v3_t *)old_params;
302
303 *n = *d; // start with a fresh copy of default parameters
304
305 memcpy(n, o, sizeof(dt_iop_lensfun_params_t) - sizeof(int));
306
307 // one more parameter and changed parameters in case we autodetect
308 n->modified = 1;
309
310 // old versions had R and B swapped
311 n->tca_r = o->tca_b;
312 n->tca_b = o->tca_r;
313
314 return 0;
315 }
316
317 if(old_version == 4 && new_version == 5)
318 {
319 typedef struct
320 {
321 int modify_flags;
322 int inverse;
323 float scale;
324 float crop;
325 float focal;
326 float aperture;
327 float distance;
328 lfLensType target_geom;
329 char camera[128];
330 char lens[128];
331 int tca_override;
332 float tca_r, tca_b;
333 int modified;
334 } dt_iop_lensfun_params_v4_t;
335
336 const dt_iop_lensfun_params_v4_t *o = (dt_iop_lensfun_params_v4_t *)old_params;
339
340 *n = *d; // start with a fresh copy of default parameters
341
342 memcpy(n, o, sizeof(dt_iop_lensfun_params_t));
343
344 // old versions had R and B swapped
345 n->tca_r = o->tca_b;
346 n->tca_b = o->tca_r;
347
348 return 0;
349 }
350
351 return 1;
352}
353
354static char *_lens_sanitize(const char *orig_lens)
355{
356 const char *found_or = strstr(orig_lens, " or ");
357 const char *found_parenthesis = strstr(orig_lens, " (");
358
359 if(found_or || found_parenthesis)
360 {
361 size_t pos_or = (size_t)(found_or - orig_lens);
362 size_t pos_parenthesis = (size_t)(found_parenthesis - orig_lens);
363 size_t pos = pos_or < pos_parenthesis ? pos_or : pos_parenthesis;
364
365 if(pos > 0)
366 {
367 char *new_lens = (char *)malloc(pos + 1);
368
369 strncpy(new_lens, orig_lens, pos);
370 new_lens[pos] = '\0';
371
372 return new_lens;
373 }
374 else
375 {
376 char *new_lens = strdup(orig_lens);
377 return new_lens;
378 }
379 }
380 else
381 {
382 char *new_lens = strdup(orig_lens);
383 return new_lens;
384 }
385}
386
388static lfModifier * get_modifier(int *mods_done, int w, int h, const dt_iop_lensfun_data_t *d, int mods_filter, gboolean force_inverse)
389{
390 lfModifier *mod;
391 int mods_todo = d->modify_flags & mods_filter;
392 int mods_done_tmp = 0;
393
394#ifdef LF_0395
395 mod = new lfModifier(d->crop, w, h, LF_PF_F32, (force_inverse) ? !d->inverse : d->inverse);
396 if(mods_todo & LF_MODIFY_DISTORTION)
397 mods_done_tmp |= mod->EnableDistortionCorrection(d->lens, d->focal);
398 if((mods_todo & LF_MODIFY_GEOMETRY) && (d->lens->Type != d->target_geom))
399 mods_done_tmp |= mod->EnableProjectionTransform(d->lens, d->focal, d->target_geom);
400 if((mods_todo & LF_MODIFY_SCALE) && (d->scale != 1.0))
401 mods_done_tmp |= mod->EnableScaling(d->scale);
402 if(mods_todo & LF_MODIFY_TCA)
403 {
404 if(d->tca_override) mods_done_tmp |= mod->EnableTCACorrection(d->custom_tca);
405 else mods_done_tmp |= mod->EnableTCACorrection(d->lens, d->focal);
406 }
407 if(mods_todo & LF_MODIFY_VIGNETTING)
408 mods_done_tmp |= mod->EnableVignettingCorrection(d->lens, d->focal, d->aperture, d->distance);
409#else
410 mod = new lfModifier(d->lens, d->crop, w, h);
411 mods_done_tmp = mod->Initialize(d->lens, LF_PF_F32, d->focal, d->aperture, d->distance, d->scale, d->target_geom, mods_todo,
412 (force_inverse) ? !d->inverse : d->inverse);
413#endif
414
415 if(mods_done) *mods_done = mods_done_tmp;
416 return mod;
417}
418
419static inline void _lens_fill_vignette_row(float *const buf, const int width, const int ch)
420{
422 {
423 const dt_aligned_pixel_simd_t half = dt_simd_set1(0.5f);
424 for(int x = 0; x < width; x++) dt_store_simd_aligned(buf + (size_t)x * ch, half);
425 }
426 else
427 {
428 for(int k = 0; k < ch * width; k++) buf[k] = 0.5f;
429 }
430}
431
432/* Why do we care about being a monochrome image or not?
433 The lensfun library does not have an algorithm for distortion or tca correction specialized for monochrome images,
434 the builtin correction works with subtle differences for the color channels leading to some colorizing of the images.
435 How is this fixed here:
436 Monochrome images (from pure monochrome cameras or cameras with the color filter removed from the sensor) have
437 all three rgb colors set to the same value by the demosaicer.
438 Looking through lensfun code & docs the ApplySubpixelGeometryDistortion algorithm makes assumptions from given
439 coeffs how far data are displaced for the different wavelengths of light.
440 As green / Y channel is the most centric i took that as the canonical value instead of taking the mean.
441*/
442
445 const void *const ivoid, void *const ovoid)
446{
447 const dt_iop_roi_t *const roi_in = &piece->roi_in;
448 const dt_iop_roi_t *const roi_out = &piece->roi_out;
449 const dt_iop_lensfun_data_t *const d = (dt_iop_lensfun_data_t *)piece->data;
451
452 const int ch = piece->dsc_in.channels;
453 const int ch_width = ch * roi_in->width;
454 const int mask_display = pipe->mask_display;
455
456 const unsigned int pixelformat = ch == 3 ? LF_CR_3(RED, GREEN, BLUE) : LF_CR_4(RED, GREEN, BLUE, UNKNOWN);
457
458 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f)
459 {
460 dt_iop_image_copy_by_size((float*)ovoid, (float*)ivoid, roi_out->width, roi_out->height, ch);
461 return 0;
462 }
463
464 const gboolean raw_monochrome = dt_image_is_monochrome(&self->dev->image_storage);
465 const int used_lf_mask = (raw_monochrome) ? LF_MODIFY_ALL & ~LF_MODIFY_TCA : LF_MODIFY_ALL;
466
467 const float orig_w = roi_in->scale * piece->buf_in.width, orig_h = roi_in->scale * piece->buf_in.height;
468
470
471 int modflags;
472 const lfModifier *modifier = get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, FALSE);
473
475
476 const struct dt_interpolation *const interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF_WARP);
477
478 if(d->inverse)
479 {
480 // reverse direction (useful for renderings)
481 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
482 {
483 // acquire temp memory for distorted pixel coords
484 const size_t bufsize = (size_t)roi_out->width * 2 * 3;
485
486 size_t padded_bufsize;
487 float *const buf = dt_pixelpipe_cache_alloc_perthread_float(bufsize, &padded_bufsize);
488 if(IS_NULL_PTR(buf)) return 1;
489
490#ifdef _OPENMP
491#pragma omp parallel for default(none) \
492 firstprivate(roi_out, roi_in, padded_bufsize, modifier, ch, d, buf, ovoid, ivoid, ch_width, interpolation, raw_monochrome, mask_display)
493#endif
494 for(int y = 0; y < roi_out->height; y++)
495 {
496 float *bufptr = (float*)dt_get_perthread(buf, padded_bufsize);
497 modifier->ApplySubpixelGeometryDistortion(roi_out->x, roi_out->y + y, roi_out->width, 1, bufptr);
498
499 // reverse transform the global coords from lf to our buffer
500 float *out = ((float *)ovoid) + (size_t)y * roi_out->width * ch;
501 for(int x = 0; x < roi_out->width; x++, bufptr += 6, out += ch)
502 {
503 dt_aligned_pixel_simd_t pixel = { 0.f };
504 for(int c = 0; c < 3; c++)
505 {
506 if(d->do_nan_checks && (!isfinite(bufptr[c * 2]) || !isfinite(bufptr[c * 2 + 1])))
507 {
508 pixel[c] = 0.0f;
509 continue;
510 }
511
512 const float *const inptr = (const float *const)ivoid + (size_t)c;
513 const float pi0 = fmaxf(fminf(bufptr[c * 2] - roi_in->x, roi_in->width - 1.0f), 0.0f);
514 const float pi1 = fmaxf(fminf(bufptr[c * 2 + 1] - roi_in->y, roi_in->height - 1.0f), 0.0f);
515 pixel[c] = dt_interpolation_compute_sample(interpolation, inptr, pi0, pi1, roi_in->width,
516 roi_in->height, ch, ch_width);
517 }
518
519 if(raw_monochrome) pixel[0] = pixel[2] = pixel[1];
520
521 if(mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK)
522 {
523 if(d->do_nan_checks && (!isfinite(bufptr[2]) || !isfinite(bufptr[3])))
524 {
525 pixel[3] = 0.0f;
526 }
527 else
528 {
529 // take green channel distortion also for alpha channel
530 const float *const inptr = (const float *const)ivoid + (size_t)3;
531 const float pi0 = fmaxf(fminf(bufptr[2] - roi_in->x, roi_in->width - 1.0f), 0.0f);
532 const float pi1 = fmaxf(fminf(bufptr[3] - roi_in->y, roi_in->height - 1.0f), 0.0f);
533 pixel[3] = dt_interpolation_compute_sample(interpolation, inptr, pi0, pi1, roi_in->width,
534 roi_in->height, ch, ch_width);
535 }
536
538 else for(int c = 0; c < ch; c++) out[c] = pixel[c];
539 }
540 else
541 {
542 for(int c = 0; c < 3; c++) out[c] = pixel[c];
543 }
544 }
545 }
547 }
548 else
549 {
550 dt_iop_image_copy_by_size((float*)ovoid, (float*)ivoid, roi_out->width, roi_out->height, ch);
551 }
552
553 if(modflags & LF_MODIFY_VIGNETTING)
554 {
555 __OMP_PARALLEL_FOR_CPP__(firstprivate(modifier, ovoid, roi_out, ch, pixelformat))
556 for(int y = 0; y < roi_out->height; y++)
557 {
558 /* Colour correction: vignetting */
559 // actually this way row stride does not matter.
560 float *out = ((float *)ovoid) + (size_t)y * roi_out->width * ch;
561 modifier->ApplyColorModification(out, roi_out->x, roi_out->y + y, roi_out->width, 1,
562 pixelformat, ch * roi_out->width);
563 }
564
565 }
566 }
567 else // correct distortions:
568 {
569 // acquire temp memory for image buffer
570 const size_t bufsize = (size_t)roi_in->width * roi_in->height * ch * sizeof(float);
572 bufsize,
573 pipe->type);
574 if(IS_NULL_PTR(buf)) return 1;
575 memcpy(buf, ivoid, bufsize);
576
577 if(modflags & LF_MODIFY_VIGNETTING)
578 {
579 __OMP_PARALLEL_FOR_CPP__(firstprivate(buf, roi_in, ch, pixelformat, modifier))
580 for(int y = 0; y < roi_in->height; y++)
581 {
582 /* Colour correction: vignetting */
583 // actually this way row stride does not matter.
584 float *bufptr = ((float *)buf) + (size_t)ch * roi_in->width * y;
585 modifier->ApplyColorModification(bufptr, roi_in->x, roi_in->y + y, roi_in->width, 1,
586 pixelformat, ch * roi_in->width);
587 }
588
589 }
590
591 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
592 {
593 // acquire temp memory for distorted pixel coords
594 const size_t buf2size = (size_t)roi_out->width * 2 * 3;
595 size_t padded_buf2size;
596 float *const buf2 = dt_pixelpipe_cache_alloc_perthread_float(buf2size, &padded_buf2size);
597 if(IS_NULL_PTR(buf2))
598 {
600 return 1;
601 }
602
603#ifdef _OPENMP
604#pragma omp parallel for default(none) \
605 firstprivate(roi_out, roi_in, ovoid, ch, padded_buf2size, modifier, mask_display, raw_monochrome, interpolation, ch_width, buf, d, buf2)
606#endif
607 for(int y = 0; y < roi_out->height; y++)
608 {
609 float *buf2ptr = (float*)dt_get_perthread(buf2, padded_buf2size);
610 modifier->ApplySubpixelGeometryDistortion(roi_out->x, roi_out->y + y, roi_out->width,
611 1, buf2ptr);
612 // reverse transform the global coords from lf to our buffer
613 float *out = ((float *)ovoid) + (size_t)y * roi_out->width * ch;
614 for(int x = 0; x < roi_out->width; x++, buf2ptr += 6, out += ch)
615 {
616 dt_aligned_pixel_simd_t pixel = { 0.f };
617 for(int c = 0; c < 3; c++)
618 {
619 if(d->do_nan_checks && (!isfinite(buf2ptr[c * 2]) || !isfinite(buf2ptr[c * 2 + 1])))
620 {
621 pixel[c] = 0.0f;
622 continue;
623 }
624
625 float *bufptr = ((float *)buf) + c;
626 const float pi0 = fmaxf(fminf(buf2ptr[c * 2] - roi_in->x, roi_in->width - 1.0f), 0.0f);
627 const float pi1 = fmaxf(fminf(buf2ptr[c * 2 + 1] - roi_in->y, roi_in->height - 1.0f), 0.0f);
628 pixel[c] = dt_interpolation_compute_sample(interpolation, bufptr, pi0, pi1, roi_in->width,
629 roi_in->height, ch, ch_width);
630 }
631 if(raw_monochrome) pixel[0] = pixel[2] = pixel[1];
632 if(mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK)
633 {
634 if(d->do_nan_checks && (!isfinite(buf2ptr[2]) || !isfinite(buf2ptr[3])))
635 {
636 pixel[3] = 0.0f;
637 }
638 else
639 {
640 // take green channel distortion also for alpha channel
641 float *bufptr = ((float *)buf) + 3;
642 const float pi0 = fmaxf(fminf(buf2ptr[2] - roi_in->x, roi_in->width - 1.0f), 0.0f);
643 const float pi1 = fmaxf(fminf(buf2ptr[3] - roi_in->y, roi_in->height - 1.0f), 0.0f);
644 pixel[3] = dt_interpolation_compute_sample(interpolation, bufptr, pi0, pi1, roi_in->width,
645 roi_in->height, ch, ch_width);
646 }
647
649 else for(int c = 0; c < ch; c++) out[c] = pixel[c];
650 }
651 else
652 {
653 for(int c = 0; c < 3; c++) out[c] = pixel[c];
654 }
655 }
656 }
658 }
659 else
660 {
661 memcpy(ovoid, buf, bufsize);
662 }
664 }
665 delete modifier;
666
667 if(self->dev->gui_attached && g && dt_dev_pixelpipe_has_preview_output(self->dev, pipe, roi_out))
668 {
670 g->corrections_done = (modflags & LENSFUN_MODFLAG_MASK);
672 }
673 return 0;
674}
675
676#ifdef HAVE_OPENCL
677int 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)
678{
679 const dt_iop_roi_t *const roi_in = &piece->roi_in;
680 const dt_iop_roi_t *const roi_out = &piece->roi_out;
684
685 const gboolean raw_monochrome = dt_image_is_monochrome(&self->dev->image_storage);
686 const int used_lf_mask = (raw_monochrome) ? LF_MODIFY_ALL & ~LF_MODIFY_TCA : LF_MODIFY_ALL;
687
688 cl_mem dev_tmpbuf = NULL;
689 cl_mem dev_tmp = NULL;
690 cl_int err = -999;
691
692 float *tmpbuf = NULL;
693 lfModifier *modifier = NULL;
694
695 const int devid = pipe->devid;
696 const int iwidth = roi_in->width;
697 const int iheight = roi_in->height;
698 const int owidth = roi_out->width;
699 const int oheight = roi_out->height;
700 const int roi_in_x = roi_in->x;
701 const int roi_in_y = roi_in->y;
702 const int width = MAX(iwidth, owidth);
703 const int height = MAX(iheight, oheight);
704 const int ch = piece->dsc_in.channels;
705 const int tmpbufwidth = owidth * 2 * 3;
706 const size_t tmpbuflen = d->inverse ? (size_t)oheight * owidth * 2 * 3 * sizeof(float)
707 : MAX((size_t)oheight * owidth * 2 * 3, (size_t)iheight * iwidth * ch)
708 * sizeof(float);
709 const unsigned int pixelformat = ch == 3 ? LF_CR_3(RED, GREEN, BLUE) : LF_CR_4(RED, GREEN, BLUE, UNKNOWN);
710
711 const float orig_w = roi_in->scale * piece->buf_in.width, orig_h = roi_in->scale * piece->buf_in.height;
712
713 size_t origin[] = { 0, 0, 0 };
714 size_t iregion[] = { (size_t)iwidth, (size_t)iheight, 1 };
715 size_t oregion[] = { (size_t)owidth, (size_t)oheight, 1 };
716 size_t isizes[] = { (size_t)ROUNDUPDWD(iwidth, devid), (size_t)ROUNDUPDHT(iheight, devid), 1 };
717 size_t osizes[] = { (size_t)ROUNDUPDWD(owidth, devid), (size_t)ROUNDUPDHT(oheight, devid), 1 };
718
719 int modflags;
720 int ldkernel = -1;
722
723 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f)
724 {
725 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, oregion);
726 if(err != CL_SUCCESS) goto error;
727 return TRUE;
728 }
729
730 switch(interpolation->id)
731 {
733 ldkernel = gd->kernel_lens_distort_bilinear;
734 break;
736 ldkernel = gd->kernel_lens_distort_bicubic;
737 break;
739 ldkernel = gd->kernel_lens_distort_mitchell;
740 break;
741 default:
742 return FALSE;
743 }
744
745 tmpbuf = (float *)dt_pixelpipe_cache_alloc_align_cache(
746 tmpbuflen,
747 pipe->type);
748 if(IS_NULL_PTR(tmpbuf)) goto error;
749
750 dev_tmp = (cl_mem)dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
751 if(IS_NULL_PTR(dev_tmp)) goto error;
752
753 dev_tmpbuf = (cl_mem)dt_opencl_alloc_device_buffer(devid, tmpbuflen);
754 if(IS_NULL_PTR(dev_tmpbuf)) goto error;
755
757 modifier = get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, FALSE);
759
760 if(d->inverse)
761 {
762 // reverse direction (useful for renderings)
763 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
764 {
765 __OMP_PARALLEL_FOR_CPP__(firstprivate(modifier, tmpbuf, roi_out, tmpbufwidth))
766 for(int y = 0; y < roi_out->height; y++)
767 {
768 float *pi = tmpbuf + (size_t)y * tmpbufwidth;
769 modifier->ApplySubpixelGeometryDistortion(roi_out->x, roi_out->y + y, roi_out->width, 1, pi);
770 }
771
772
773 /* _blocking_ memory transfer: host tmpbuf buffer -> opencl dev_tmpbuf */
774 err = dt_opencl_write_buffer_to_device(devid, tmpbuf, dev_tmpbuf, 0,
775 (size_t)owidth * oheight * 2 * 3 * sizeof(float), CL_TRUE);
776 if(err != CL_SUCCESS) goto error;
777
778 dt_opencl_set_kernel_arg(devid, ldkernel, 0, sizeof(cl_mem), (void *)&dev_in);
779 dt_opencl_set_kernel_arg(devid, ldkernel, 1, sizeof(cl_mem), (void *)&dev_tmp);
780 dt_opencl_set_kernel_arg(devid, ldkernel, 2, sizeof(int), (void *)&owidth);
781 dt_opencl_set_kernel_arg(devid, ldkernel, 3, sizeof(int), (void *)&oheight);
782 dt_opencl_set_kernel_arg(devid, ldkernel, 4, sizeof(int), (void *)&iwidth);
783 dt_opencl_set_kernel_arg(devid, ldkernel, 5, sizeof(int), (void *)&iheight);
784 dt_opencl_set_kernel_arg(devid, ldkernel, 6, sizeof(int), (void *)&roi_in_x);
785 dt_opencl_set_kernel_arg(devid, ldkernel, 7, sizeof(int), (void *)&roi_in_y);
786 dt_opencl_set_kernel_arg(devid, ldkernel, 8, sizeof(cl_mem), (void *)&dev_tmpbuf);
787 dt_opencl_set_kernel_arg(devid, ldkernel, 9, sizeof(int), (void *)&(d->do_nan_checks));
788 dt_opencl_set_kernel_arg(devid, ldkernel, 10, sizeof(int), (void *)&(raw_monochrome));
789 err = dt_opencl_enqueue_kernel_2d(devid, ldkernel, osizes);
790 if(err != CL_SUCCESS) goto error;
791 }
792 else
793 {
794 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_tmp, origin, origin, oregion);
795 if(err != CL_SUCCESS) goto error;
796 }
797
798 if(modflags & LF_MODIFY_VIGNETTING)
799 {
800 __OMP_PARALLEL_FOR_CPP__(firstprivate(modifier, tmpbuf, roi_out, pixelformat, ch))
801 for(int y = 0; y < roi_out->height; y++)
802 {
803 /* Colour correction: vignetting */
804 // actually this way row stride does not matter.
805 float *buf = tmpbuf + (size_t)y * ch * roi_out->width;
806 _lens_fill_vignette_row(buf, roi_out->width, ch);
807 modifier->ApplyColorModification(buf, roi_out->x, roi_out->y + y, roi_out->width, 1,
808 pixelformat, ch * roi_out->width);
809 }
810
811
812 /* _blocking_ memory transfer: host tmpbuf buffer -> opencl dev_tmpbuf */
813 err = dt_opencl_write_buffer_to_device(devid, tmpbuf, dev_tmpbuf, 0,
814 (size_t)ch * roi_out->width * roi_out->height * sizeof(float),
815 CL_TRUE);
816 if(err != CL_SUCCESS) goto error;
817
818 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 0, sizeof(cl_mem), (void *)&dev_tmp);
819 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 1, sizeof(cl_mem), (void *)&dev_out);
820 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 2, sizeof(int), (void *)&owidth);
821 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 3, sizeof(int), (void *)&oheight);
822 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 4, sizeof(cl_mem), (void *)&dev_tmpbuf);
823 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_lens_vignette, osizes);
824 if(err != CL_SUCCESS) goto error;
825 }
826 else
827 {
828 err = dt_opencl_enqueue_copy_image(devid, dev_tmp, dev_out, origin, origin, oregion);
829 if(err != CL_SUCCESS) goto error;
830 }
831 }
832
833 else // correct distortions:
834 {
835
836 if(modflags & LF_MODIFY_VIGNETTING)
837 {
838 __OMP_PARALLEL_FOR_CPP__(firstprivate(tmpbuf, ch, roi_in, pixelformat, modifier))
839 for(int y = 0; y < roi_in->height; y++)
840 {
841 /* Colour correction: vignetting */
842 // actually this way row stride does not matter.
843 float *buf = tmpbuf + (size_t)y * ch * roi_in->width;
844 _lens_fill_vignette_row(buf, roi_in->width, ch);
845 modifier->ApplyColorModification(buf, roi_in->x, roi_in->y + y, roi_in->width, 1,
846 pixelformat, ch * roi_in->width);
847 }
848
849
850 /* _blocking_ memory transfer: host tmpbuf buffer -> opencl dev_tmpbuf */
852 devid, tmpbuf, dev_tmpbuf, 0, (size_t)ch * roi_in->width * roi_in->height * sizeof(float), CL_TRUE);
853 if(err != CL_SUCCESS) goto error;
854
855 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 0, sizeof(cl_mem), (void *)&dev_in);
856 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 1, sizeof(cl_mem), (void *)&dev_tmp);
857 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 2, sizeof(int), (void *)&iwidth);
858 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 3, sizeof(int), (void *)&iheight);
859 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 4, sizeof(cl_mem), (void *)&dev_tmpbuf);
860 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_lens_vignette, isizes);
861 if(err != CL_SUCCESS) goto error;
862 }
863 else
864 {
865 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_tmp, origin, origin, iregion);
866 if(err != CL_SUCCESS) goto error;
867 }
868
869 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
870 {
871 __OMP_PARALLEL_FOR_CPP__(firstprivate(modifier, roi_out, tmpbuf, tmpbufwidth))
872 for(int y = 0; y < roi_out->height; y++)
873 {
874 float *pi = tmpbuf + (size_t)y * tmpbufwidth;
875 modifier->ApplySubpixelGeometryDistortion(roi_out->x, roi_out->y + y, roi_out->width, 1, pi);
876 }
877
878
879 /* _blocking_ memory transfer: host tmpbuf buffer -> opencl dev_tmpbuf */
880 err = dt_opencl_write_buffer_to_device(devid, tmpbuf, dev_tmpbuf, 0,
881 (size_t)owidth * oheight * 2 * 3 * sizeof(float), CL_TRUE);
882 if(err != CL_SUCCESS) goto error;
883
884 dt_opencl_set_kernel_arg(devid, ldkernel, 0, sizeof(cl_mem), (void *)&dev_tmp);
885 dt_opencl_set_kernel_arg(devid, ldkernel, 1, sizeof(cl_mem), (void *)&dev_out);
886 dt_opencl_set_kernel_arg(devid, ldkernel, 2, sizeof(int), (void *)&owidth);
887 dt_opencl_set_kernel_arg(devid, ldkernel, 3, sizeof(int), (void *)&oheight);
888 dt_opencl_set_kernel_arg(devid, ldkernel, 4, sizeof(int), (void *)&iwidth);
889 dt_opencl_set_kernel_arg(devid, ldkernel, 5, sizeof(int), (void *)&iheight);
890 dt_opencl_set_kernel_arg(devid, ldkernel, 6, sizeof(int), (void *)&roi_in_x);
891 dt_opencl_set_kernel_arg(devid, ldkernel, 7, sizeof(int), (void *)&roi_in_y);
892 dt_opencl_set_kernel_arg(devid, ldkernel, 8, sizeof(cl_mem), (void *)&dev_tmpbuf);
893 dt_opencl_set_kernel_arg(devid, ldkernel, 9, sizeof(int), (void *)&(d->do_nan_checks));
894 dt_opencl_set_kernel_arg(devid, ldkernel, 10, sizeof(int), (void *)&(raw_monochrome));
895 err = dt_opencl_enqueue_kernel_2d(devid, ldkernel, osizes);
896 if(err != CL_SUCCESS) goto error;
897 }
898 else
899 {
900 err = dt_opencl_enqueue_copy_image(devid, dev_tmp, dev_out, origin, origin, oregion);
901 if(err != CL_SUCCESS) goto error;
902 }
903 }
904
905 if(self->dev->gui_attached && g && dt_dev_pixelpipe_has_preview_output(self->dev, pipe, roi_out))
906 {
908 g->corrections_done = (modflags & LENSFUN_MODFLAG_MASK);
910 }
911
915 if(!IS_NULL_PTR(modifier)) delete modifier;
916 return TRUE;
917
918error:
922 if(!IS_NULL_PTR(modifier)) delete modifier;
923 dt_print(DT_DEBUG_OPENCL, "[opencl_lens] couldn't enqueue kernel! %d\n", err);
924 return FALSE;
925}
926#endif
927
928void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
929{
930 tiling->factor = 4.5f; // in + out + tmp + tmpbuf
931 tiling->maxbuf = 1.5f;
932 tiling->overhead = 0;
933 tiling->overlap = 4;
934 tiling->xalign = 1;
935 tiling->yalign = 1;
936 return;
937}
938
940 float *const __restrict points, size_t points_count)
941{
943 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f) return 0;
944
945 const float orig_w = piece->buf_in.width, orig_h = piece->buf_in.height;
946 int modflags;
947
948 const int used_lf_mask = (dt_image_is_monochrome(&self->dev->image_storage)) ? LF_MODIFY_ALL & ~LF_MODIFY_TCA : LF_MODIFY_ALL;
949
950 const lfModifier *modifier = get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, TRUE);
951 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
952 {
953 __OMP_PARALLEL_FOR_CPP__(firstprivate(points, points_count, modifier) if(points_count > 100))
954 for(size_t i = 0; i < points_count * 2; i += 2)
955 {
956 float DT_ALIGNED_ARRAY buf[6];
957 modifier->ApplySubpixelGeometryDistortion(points[i], points[i + 1], 1, 1, buf);
958 points[i] = buf[0];
959 points[i + 1] = buf[3];
960 }
961
962 }
963
964 delete modifier;
965 return 1;
966}
967
969 float *const __restrict points, size_t points_count)
970{
972
973 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f) return 0;
974
975 const int used_lf_mask = (dt_image_is_monochrome(&self->dev->image_storage)) ? LF_MODIFY_ALL & ~LF_MODIFY_TCA : LF_MODIFY_ALL;
976
977 const float orig_w = piece->buf_in.width, orig_h = piece->buf_in.height;
978 int modflags;
979 const lfModifier *modifier = get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, FALSE);
980
981 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
982 {
983 __OMP_PARALLEL_FOR_CPP__(firstprivate(points_count, modifier, points) if(points_count > 100))
984 for(size_t i = 0; i < points_count * 2; i += 2)
985 {
986 float DT_ALIGNED_ARRAY buf[6];
987 modifier->ApplySubpixelGeometryDistortion(points[i], points[i + 1], 1, 1, buf);
988 points[i] = buf[0];
989 points[i + 1] = buf[3];
990 }
991
992 }
993
994 delete modifier;
995 return 1;
996}
997
998// TODO: Shall we keep LF_MODIFY_TCA in the modifiers?
999void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece,
1000 const float *const in, float *const out, const dt_iop_roi_t *const roi_in,
1001 const dt_iop_roi_t *const roi_out)
1002{
1003 (void)pipe;
1004 const dt_iop_lensfun_data_t *const d = (dt_iop_lensfun_data_t *)piece->data;
1005
1006 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f)
1007 {
1008 dt_iop_image_copy_by_size(out, in, roi_out->width, roi_out->height, 1);
1009 return;
1010 }
1011
1012 const float orig_w = roi_in->scale * piece->buf_in.width, orig_h = roi_in->scale * piece->buf_in.height;
1014 int modflags;
1015 const lfModifier *modifier = get_modifier(&modflags, orig_w, orig_h, d, /*LF_MODIFY_TCA |*/ LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE, FALSE);
1016
1018
1019 if(!(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE)))
1020 {
1021 dt_iop_image_copy_by_size(out, in, roi_out->width, roi_out->height, 1);
1022 delete modifier;
1023 return;
1024 }
1025
1026 const struct dt_interpolation *const interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF_WARP);
1027
1028 // acquire temp memory for distorted pixel coords
1029 const size_t bufsize = (size_t)roi_out->width * 2 * 3;
1030 size_t padded_bufsize;
1031 float *const buf = dt_pixelpipe_cache_alloc_perthread_float(bufsize, &padded_bufsize);
1032 if(IS_NULL_PTR(buf)) return;
1033 __OMP_PARALLEL_FOR_CPP__(firstprivate(buf, padded_bufsize, d, modifier, in, out, interpolation, roi_in, roi_out))
1034 for(int y = 0; y < roi_out->height; y++)
1035 {
1036 float *bufptr = (float*)dt_get_perthread(buf, padded_bufsize);
1037 modifier->ApplySubpixelGeometryDistortion(roi_out->x, roi_out->y + y, roi_out->width, 1, bufptr);
1038
1039 // reverse transform the global coords from lf to our buffer
1040 float *_out = out + (size_t)y * roi_out->width;
1041 for(int x = 0; x < roi_out->width; x++, bufptr += 6, _out++)
1042 {
1043 if(d->do_nan_checks && (!isfinite(bufptr[2]) || !isfinite(bufptr[3])))
1044 {
1045 *_out = 0.0f;
1046 continue;
1047 }
1048
1049 // take green channel distortion also for alpha channel
1050 const float pi0 = bufptr[2] - roi_in->x;
1051 const float pi1 = bufptr[3] - roi_in->y;
1052 *_out = dt_interpolation_compute_sample(interpolation, in, pi0, pi1, roi_in->width, roi_in->height, 1,
1053 roi_in->width);
1054 }
1055 }
1056
1057
1059 delete modifier;
1060}
1061
1062void modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1063 struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out,
1064 const dt_iop_roi_t *roi_in)
1065{
1066 *roi_out = *roi_in;
1067}
1068
1069void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1070 struct dt_dev_pixelpipe_iop_t *piece,
1071 const dt_iop_roi_t *const roi_out, dt_iop_roi_t *roi_in)
1072{
1074 *roi_in = *roi_out;
1075 // inverse transform with given params
1076
1077 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f) return;
1078
1079 const float orig_w = roi_in->scale * piece->buf_in.width;
1080 const float orig_h = roi_in->scale * piece->buf_in.height;
1081 int modflags;
1082 const lfModifier *modifier = get_modifier(&modflags, orig_w, orig_h, d, LF_MODIFY_ALL, FALSE);
1083
1084 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
1085 {
1086 const int xoff = roi_in->x;
1087 const int yoff = roi_in->y;
1088 const int width = roi_in->width;
1089 const int height = roi_in->height;
1090 const int awidth = abs(width);
1091 const int aheight = abs(height);
1092 const int xstep = (width < 0) ? -1 : 1;
1093 const int ystep = (height < 0) ? -1 : 1;
1094
1095 float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX;
1096 const size_t nbpoints = 2 * awidth + 2 * aheight;
1097
1098 // ROI planning passes the active pipe now, but this temporary edge buffer only needs an
1099 // allocator bucket id, so use a stable generic bucket.
1100 float *const buf = (float *)dt_pixelpipe_cache_alloc_align_cache(sizeof(float) * nbpoints * 2 * 3,
1102 if(IS_NULL_PTR(buf)) return;
1103
1104#ifdef _OPENMP
1105#pragma omp parallel default(none) reduction(min : xm, ym) reduction(max : xM, yM) \
1106 firstprivate(modifier, xoff, yoff, awidth, aheight, width, height, nbpoints, ystep, xstep, buf)
1107#endif
1108 {
1109 __OMP_FOR__()
1110 for(int i = 0; i < awidth; i++)
1111 modifier->ApplySubpixelGeometryDistortion(xoff + i * xstep, yoff, 1, 1, buf + 6 * i);
1112 __OMP_FOR__()
1113 for(int i = 0; i < awidth; i++)
1114 modifier->ApplySubpixelGeometryDistortion(xoff + i * xstep, yoff + (height - 1), 1, 1, buf + 6 * (awidth + i));
1115 __OMP_FOR__()
1116 for(int j = 0; j < aheight; j++)
1117 modifier->ApplySubpixelGeometryDistortion(xoff, yoff + j * ystep, 1, 1, buf + 6 * (2 * awidth + j));
1118 __OMP_FOR__()
1119 for(int j = 0; j < aheight; j++)
1120 modifier->ApplySubpixelGeometryDistortion(xoff + (width - 1), yoff + j * ystep, 1, 1, buf + 6 * (2 * awidth + aheight + j));
1121
1122#ifdef _OPENMP
1123#pragma omp barrier
1124#endif
1125 __OMP_FOR__()
1126 for(size_t k = 0; k < nbpoints; k++)
1127 {
1128 // iterate over RGB channels x and y coordinates
1129 for(size_t c = 0; c < 6; c+=2)
1130 {
1131 const float x = buf[6 * k + c];
1132 const float y = buf[6 * k + c + 1];
1133 xm = isnan(x) ? xm : MIN(xm, x);
1134 xM = isnan(x) ? xM : MAX(xM, x);
1135 ym = isnan(y) ? ym : MIN(ym, y);
1136 yM = isnan(y) ? yM : MAX(yM, y);
1137 }
1138 }
1139 }
1140
1142
1143 // LensFun can return NAN coords, so we need to handle them carefully.
1144 if(!isfinite(xm) || !(0 <= xm && xm < orig_w)) xm = 0;
1145 if(!isfinite(xM) || !(1 <= xM && xM < orig_w)) xM = orig_w;
1146 if(!isfinite(ym) || !(0 <= ym && ym < orig_h)) ym = 0;
1147 if(!isfinite(yM) || !(1 <= yM && yM < orig_h)) yM = orig_h;
1148
1150 roi_in->x = fmaxf(0.0f, roundf(xm - interpolation->width));
1151 roi_in->y = fmaxf(0.0f, roundf(ym - interpolation->width));
1152 roi_in->width = roundf(fminf(orig_w - roi_in->x, xM - roi_in->x + interpolation->width));
1153 roi_in->height = roundf(fminf(orig_h - roi_in->y, yM - roi_in->y + interpolation->width));
1154
1155 // sanity check.
1156 roi_in->x = CLAMP(roi_in->x, 0, (int)floorf(orig_w));
1157 roi_in->y = CLAMP(roi_in->y, 0, (int)floorf(orig_h));
1158 roi_in->width = CLAMP(roi_in->width, 1, (int)ceilf(orig_w) - roi_in->x);
1159 roi_in->height = CLAMP(roi_in->height, 1, (int)ceilf(orig_h) - roi_in->y);
1160 }
1161 delete modifier;
1162}
1163
1166{
1168
1169 // FIXME: this is utter shit and should be made into a GUI "mode".
1170 // If p->modified == 0, mode = auto and hide all controls
1171 // if p->modidified == 1, mode = manual and show all controls.
1172 if(p->modified == 0)
1173 {
1174 /*
1175 * user did not modify anything in gui after autodetection - let's
1176 * use current default_params as params - for presets and mass-export
1177 */
1179
1180 // Temporary fix pending GUI unfucking
1181 dt_iop_compute_module_hash(self, self->dev->forms);
1182 }
1183
1185
1187 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
1188 const lfCamera *camera = NULL;
1189 const lfCamera **cam = NULL;
1190 if(d->lens)
1191 {
1192 delete d->lens;
1193 d->lens = NULL;
1194 }
1195 d->lens = new lfLens;
1196
1197 if(p->camera[0])
1198 {
1200 cam = dt_iop_lensfun_db->FindCamerasExt(NULL, p->camera, 0);
1201 if(cam)
1202 {
1203 camera = cam[0];
1204 d->crop = cam[0]->CropFactor;
1205 }
1207 }
1208 if(p->lens[0])
1209 {
1211 const lfLens **lens
1212 = dt_iop_lensfun_db->FindLenses(camera, NULL, p->lens, 0);
1214 if(lens)
1215 {
1216 *d->lens = *lens[0];
1217 if(p->tca_override)
1218 {
1219#ifdef LF_0395
1220 const dt_image_t *img = &(self->dev->image_storage);
1221
1222 d->custom_tca =
1223 {
1224 .Model = LF_TCA_MODEL_LINEAR,
1225 .Focal = p->focal,
1226 .Terms = { p->tca_r, p->tca_b },
1227 .CalibAttr = {
1228 .CenterX = 0.0f,
1229 .CenterY = 0.0f,
1230 .CropFactor = d->crop,
1231 .AspectRatio = (float)img->width / (float)img->height
1232 }
1233 };
1234#else
1235 // add manual d->lens stuff:
1236 lfLensCalibTCA tca = { LF_TCA_MODEL_NONE };
1237 tca.Focal = 0;
1238 tca.Model = LF_TCA_MODEL_LINEAR;
1239 tca.Terms[0] = p->tca_r;
1240 tca.Terms[1] = p->tca_b;
1241 if(d->lens->CalibTCA)
1242 while(d->lens->CalibTCA[0]) d->lens->RemoveCalibTCA(0);
1243 d->lens->AddCalibTCA(&tca);
1244#endif
1245 }
1246 lf_free(lens);
1247 }
1248 }
1249 lf_free(cam);
1250 d->modify_flags = p->modify_flags;
1251 if(dt_image_is_monochrome(&self->dev->image_storage)) d->modify_flags &= ~LF_MODIFY_TCA;
1252 d->inverse = p->inverse;
1253 d->scale = p->scale;
1254 d->focal = p->focal;
1255 d->aperture = p->aperture;
1256 d->distance = p->distance;
1257 d->target_geom = p->target_geom;
1258 d->do_nan_checks = TRUE;
1259 d->tca_override = p->tca_override;
1260
1261 /*
1262 * there are certain situations when LensFun can return NAN coordinated.
1263 * most common case would be when the FOV is increased.
1264 */
1265 if(d->target_geom == LF_RECTILINEAR)
1266 {
1267 d->do_nan_checks = FALSE;
1268 }
1269 else if(d->target_geom == d->lens->Type)
1270 {
1271 d->do_nan_checks = FALSE;
1272 }
1273
1274 piece->cache_output_on_ram = TRUE;
1275}
1276
1278{
1279 piece->data = dt_calloc_align(sizeof(dt_iop_lensfun_data_t));
1280 piece->data_size = sizeof(dt_iop_lensfun_data_t);
1281}
1282
1284{
1286
1287 if(d->lens)
1288 {
1289 delete d->lens;
1290 d->lens = NULL;
1291 }
1292 dt_free_align(piece->data);
1293 piece->data = NULL;
1294}
1295
1297{
1298 const int program = 2; // basic.cl, from programs.conf
1301 module->data = gd;
1302 gd->kernel_lens_distort_bilinear = dt_opencl_create_kernel(program, "lens_distort_bilinear");
1303 gd->kernel_lens_distort_bicubic = dt_opencl_create_kernel(program, "lens_distort_bicubic");
1304 gd->kernel_lens_distort_mitchell = dt_opencl_create_kernel(program, "lens_distort_mitchell");
1305 gd->kernel_lens_vignette = dt_opencl_create_kernel(program, "lens_vignette");
1306
1307 lfDatabase *dt_iop_lensfun_db = new lfDatabase;
1308 gd->db = (lfDatabase *)dt_iop_lensfun_db;
1309
1310#if defined(__MACH__) || defined(__APPLE__)
1311#else
1312 if(dt_iop_lensfun_db->Load() != LF_NO_ERROR)
1313#endif
1314 {
1315 char datadir[PATH_MAX] = { 0 };
1316 dt_loc_get_datadir(datadir, sizeof(datadir));
1317
1318 // get parent directory
1319 GFile *file = g_file_parse_name(datadir);
1320 GFile *parent = g_file_get_parent(file);
1321 gchar *path = g_file_get_path(parent);
1322 g_object_unref(parent);
1323 g_object_unref(file);
1324#ifdef LF_MAX_DATABASE_VERSION
1325 gchar *sysdbpath = g_build_filename(path, "lensfun", "version_" STR(LF_MAX_DATABASE_VERSION), (char *)NULL);
1326#endif
1327
1328#ifdef LF_0395
1329 const long userdbts = dt_iop_lensfun_db->ReadTimestamp(dt_iop_lensfun_db->UserUpdatesLocation);
1330 const long sysdbts = dt_iop_lensfun_db->ReadTimestamp(sysdbpath);
1331 const char *dbpath = userdbts > sysdbts ? dt_iop_lensfun_db->UserUpdatesLocation : sysdbpath;
1332 if(dt_iop_lensfun_db->Load(dbpath) != LF_NO_ERROR)
1333 fprintf(stderr, "[iop_lens]: could not load lensfun database in `%s'!\n", dbpath);
1334 else
1335 dt_iop_lensfun_db->Load(dt_iop_lensfun_db->UserLocation);
1336#else
1337 // code for older lensfun preserved as-is
1338#ifdef LF_MAX_DATABASE_VERSION
1339 dt_free(dt_iop_lensfun_db->HomeDataDir);
1340 dt_iop_lensfun_db->HomeDataDir = g_strdup(sysdbpath);
1341 if(dt_iop_lensfun_db->Load() != LF_NO_ERROR)
1342 {
1343 fprintf(stderr, "[iop_lens]: could not load lensfun database in `%s'!\n", sysdbpath);
1344#endif
1345 dt_free(dt_iop_lensfun_db->HomeDataDir);
1346 dt_iop_lensfun_db->HomeDataDir = g_build_filename(path, "lensfun", (char *)NULL);
1347 if(dt_iop_lensfun_db->Load() != LF_NO_ERROR)
1348 fprintf(stderr, "[iop_lens]: could not load lensfun database in `%s'!\n", dt_iop_lensfun_db->HomeDataDir);
1349#ifdef LF_MAX_DATABASE_VERSION
1350 }
1351#endif
1352#endif
1353
1354#ifdef LF_MAX_DATABASE_VERSION
1355 dt_free(sysdbpath);
1356#endif
1357 dt_free(path);
1358 }
1359}
1360
1361static float get_autoscale(dt_iop_module_t *self, dt_iop_lensfun_params_t *p, const lfCamera *camera);
1362
1364{
1365 char *new_lens;
1366 const dt_image_t *img = &module->dev->image_storage;
1367
1368 // reload image specific stuff
1369 // get all we can from exif:
1371
1372 new_lens = _lens_sanitize(img->exif_lens);
1373 g_strlcpy(d->lens, new_lens, sizeof(d->lens));
1374 dt_free(new_lens);
1375 g_strlcpy(d->camera, img->exif_model, sizeof(d->camera));
1376 d->crop = img->exif_crop;
1377 d->aperture = img->exif_aperture;
1378 d->focal = img->exif_focal_length;
1379 d->scale = 1.0;
1380 d->modify_flags = LF_MODIFY_TCA | LF_MODIFY_VIGNETTING | LF_MODIFY_DISTORTION |
1381 LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE;
1382 // if we did not find focus_distance in EXIF, lets default to 1000
1383 d->distance = img->exif_focus_distance == 0.0f ? 1000.0f : img->exif_focus_distance;
1384 d->target_geom = LF_RECTILINEAR;
1385
1386 if(dt_image_is_monochrome(img))
1387 d->modify_flags &= ~LF_MODIFY_TCA;
1388
1389 // init crop from db:
1390 char model[100]; // truncate often complex descriptions.
1391 g_strlcpy(model, img->exif_model, sizeof(model));
1392 for(char cnt = 0, *c = model; c < model + 100 && *c != '\0'; c++)
1393 if(*c == ' ')
1394 if(++cnt == 2) *c = '\0';
1395 if(img->exif_maker[0] || model[0])
1396 {
1398
1399 // just to be sure
1400 if(IS_NULL_PTR(gd) || IS_NULL_PTR(gd->db)) return;
1401
1403 const lfCamera **cam = gd->db->FindCamerasExt(img->exif_maker, img->exif_model, 0);
1405 if(cam)
1406 {
1408 const lfLens **lens = gd->db->FindLenses(cam[0], NULL, d->lens, 0);
1410
1411 if(!lens && islower(cam[0]->Mount[0]))
1412 {
1413 /*
1414 * This is a fixed-lens camera, and LF returned no lens.
1415 * (reasons: lens is "(65535)" or lens is correct lens name,
1416 * but LF have it as "fixed lens")
1417 *
1418 * Let's unset lens name and re-run lens query
1419 */
1420 g_strlcpy(d->lens, "", sizeof(d->lens));
1421
1423 lens = gd->db->FindLenses(cam[0], NULL, d->lens, 0);
1425 }
1426
1427 if(lens)
1428 {
1429 int lens_i = 0;
1430
1431 /*
1432 * Current SVN lensfun lets you test for a fixed-lens camera by looking
1433 * at the zeroth character in the mount's name:
1434 * If it is a lower case letter, it is a fixed-lens camera.
1435 */
1436 if(!d->lens[0] && islower(cam[0]->Mount[0]))
1437 {
1438 /*
1439 * no lens info in EXIF, and this is fixed-lens camera,
1440 * let's find shortest lens model in the list of possible lenses
1441 */
1442 size_t min_model_len = SIZE_MAX;
1443 for(int i = 0; lens[i]; i++)
1444 {
1445 if(strlen(lens[i]->Model) < min_model_len)
1446 {
1447 min_model_len = strlen(lens[i]->Model);
1448 lens_i = i;
1449 }
1450 }
1451
1452 // and set lens to it
1453 g_strlcpy(d->lens, lens[lens_i]->Model, sizeof(d->lens));
1454 }
1455
1456 d->target_geom = lens[lens_i]->Type;
1457 lf_free(lens);
1458 }
1459
1460 d->crop = cam[0]->CropFactor;
1461 d->scale = get_autoscale(module, d, cam[0]);
1462 module->workflow_enabled = TRUE;
1463 lf_free(cam);
1464 }
1465 }
1466
1467 // if we have a gui -> reset corrections_done message
1469 if(g)
1470 {
1472 g->corrections_done = -1;
1474 gtk_label_set_text(g->message, "");
1475 }
1476}
1477
1479{
1481 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
1482 delete dt_iop_lensfun_db;
1483
1488 dt_free(module->data);
1489}
1490
1493
1494/* simple function to compute the floating-point precision
1495 which is enough for "normal use". The criteria is to have
1496 about 3 leading digits after the initial zeros. */
1497static int precision(double x, double adj)
1498{
1499 x *= adj;
1500
1501 if(x == 0) return 1;
1502 if(x < 1.0)
1503 if(x < 0.1)
1504 if(x < 0.01)
1505 return 5;
1506 else
1507 return 4;
1508 else
1509 return 3;
1510 else if(x < 100.0)
1511 if(x < 10.0)
1512 return 2;
1513 else
1514 return 1;
1515 else
1516 return 0;
1517}
1518
1519/* -- ufraw ptr array functions -- */
1520
1521static int ptr_array_insert_sorted(GPtrArray *array, const void *item, GCompareFunc compare)
1522{
1523 int length = array->len;
1524 g_ptr_array_set_size(array, length + 1);
1525 const void **root = (const void **)array->pdata;
1526
1527 int m = 0, l = 0, r = length - 1;
1528
1529 // Skip trailing NULL, if any
1530 if(l <= r && !root[r]) r--;
1531
1532 while(l <= r)
1533 {
1534 m = (l + r) / 2;
1535 int cmp = compare(root[m], item);
1536
1537 if(cmp == 0)
1538 {
1539 ++m;
1540 goto done;
1541 }
1542 else if(cmp < 0)
1543 l = m + 1;
1544 else
1545 r = m - 1;
1546 }
1547 if(r == m) m++;
1548
1549done:
1550 memmove(root + m + 1, root + m, sizeof(void *) * (length - m));
1551 root[m] = item;
1552 return m;
1553}
1554
1555static int ptr_array_find_sorted(const GPtrArray *array, const void *item, GCompareFunc compare)
1556{
1557 int length = array->len;
1558 void **root = array->pdata;
1559
1560 int l = 0, r = length - 1;
1561 int m = 0, cmp = 0;
1562
1563 if(!length) return -1;
1564
1565 // Skip trailing NULL, if any
1566 if(!root[r]) r--;
1567
1568 while(l <= r)
1569 {
1570 m = (l + r) / 2;
1571 cmp = compare(root[m], item);
1572
1573 if(cmp == 0)
1574 return m;
1575 else if(cmp < 0)
1576 l = m + 1;
1577 else
1578 r = m - 1;
1579 }
1580
1581 return -1;
1582}
1583
1584static void ptr_array_insert_index(GPtrArray *array, const void *item, int index)
1585{
1586 const void **root;
1587 int length = array->len;
1588 g_ptr_array_set_size(array, length + 1);
1589 root = (const void **)array->pdata;
1590 memmove(root + index + 1, root + index, sizeof(void *) * (length - index));
1591 root[index] = item;
1592}
1593
1594/* -- end ufraw ptr array functions -- */
1595
1596/* -- camera -- */
1597
1598static void camera_set(dt_iop_module_t *self, const lfCamera *cam)
1599{
1602 gchar *fm;
1603 const char *maker, *model, *variant;
1604 char _variant[100];
1605
1606 if(IS_NULL_PTR(cam))
1607 {
1608 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->camera_model))), "");
1609 gtk_widget_set_tooltip_text(GTK_WIDGET(g->camera_model), "");
1610 return;
1611 }
1612
1613 g_strlcpy(p->camera, cam->Model, sizeof(p->camera));
1614 p->crop = cam->CropFactor;
1615 g->camera = cam;
1616
1617 maker = lf_mlstr_get(cam->Maker);
1618 model = lf_mlstr_get(cam->Model);
1619 variant = lf_mlstr_get(cam->Variant);
1620
1621 if(model)
1622 {
1623 if(maker)
1624 fm = g_strdup_printf("%s, %s", maker, model);
1625 else
1626 fm = g_strdup_printf("%s", model);
1627 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->camera_model))), fm);
1628 dt_free(fm);
1629 }
1630
1631 if(variant)
1632 snprintf(_variant, sizeof(_variant), " (%s)", variant);
1633 else
1634 _variant[0] = 0;
1635
1636 fm = g_strdup_printf(_("maker:\t\t%s\n"
1637 "model:\t\t%s%s\n"
1638 "mount:\t\t%s\n"
1639 "crop factor:\t%.1f"),
1640 maker, model, _variant, cam->Mount, cam->CropFactor);
1641 gtk_widget_set_tooltip_text(GTK_WIDGET(g->camera_model), fm);
1642 dt_free(fm);
1643}
1644
1645static void camera_menu_select(GtkMenuItem *menuitem, gpointer user_data)
1646{
1647 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1648 camera_set(self, (lfCamera *)g_object_get_data(G_OBJECT(menuitem), "lfCamera"));
1649 if(darktable.gui->reset) return;
1651 p->modified = 1;
1653}
1654
1655static void camera_menu_fill(dt_iop_module_t *self, const lfCamera *const *camlist)
1656{
1658 unsigned i;
1659 GPtrArray *makers, *submenus;
1660
1661 if(g->camera_menu)
1662 {
1663 gtk_widget_destroy(GTK_WIDGET(g->camera_menu));
1664 g->camera_menu = NULL;
1665 }
1666
1667 /* Count all existing camera makers and create a sorted list */
1668 makers = g_ptr_array_new();
1669 submenus = g_ptr_array_new();
1670 for(i = 0; camlist[i]; i++)
1671 {
1672 GtkWidget *submenu, *item;
1673 const char *m = lf_mlstr_get(camlist[i]->Maker);
1674 int idx = ptr_array_find_sorted(makers, m, (GCompareFunc)g_utf8_collate);
1675 if(idx < 0)
1676 {
1677 /* No such maker yet, insert it into the array */
1678 idx = ptr_array_insert_sorted(makers, m, (GCompareFunc)g_utf8_collate);
1679 /* Create a submenu for cameras by this maker */
1680 submenu = gtk_menu_new();
1681 ptr_array_insert_index(submenus, submenu, idx);
1682 }
1683
1684 submenu = (GtkWidget *)g_ptr_array_index(submenus, idx);
1685 /* Append current camera name to the submenu */
1686 m = lf_mlstr_get(camlist[i]->Model);
1687 if(!camlist[i]->Variant)
1688 item = gtk_menu_item_new_with_label(m);
1689 else
1690 {
1691 gchar *fm = g_strdup_printf("%s (%s)", m, camlist[i]->Variant);
1692 item = gtk_menu_item_new_with_label(fm);
1693 dt_free(fm);
1694 }
1695 gtk_widget_show(item);
1696 g_object_set_data(G_OBJECT(item), "lfCamera", (void *)camlist[i]);
1697 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(camera_menu_select), self);
1698 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
1699 }
1700
1701 g->camera_menu = GTK_MENU(gtk_menu_new());
1702 for(i = 0; i < makers->len; i++)
1703 {
1704 GtkWidget *item = (GtkWidget *)gtk_menu_item_new_with_label((const gchar *)g_ptr_array_index(makers, i));
1705 gtk_widget_show(item);
1706 gtk_menu_shell_append(GTK_MENU_SHELL(g->camera_menu), item);
1707 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), (GtkWidget *)g_ptr_array_index(submenus, i));
1708 }
1709
1710 g_ptr_array_free(submenus, TRUE);
1711 g_ptr_array_free(makers, TRUE);
1712}
1713
1714static void parse_model(const char *txt, char *model, size_t sz_model)
1715{
1716 while(txt[0] && isspace(txt[0])) txt++;
1717 size_t len = strlen(txt);
1718 if(len > sz_model - 1) len = sz_model - 1;
1719 memcpy(model, txt, len);
1720 model[len] = 0;
1721}
1722
1723static void camera_menusearch_clicked(GtkWidget *button, gpointer user_data)
1724{
1725 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1727 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
1729
1730 (void)button;
1731
1732 const lfCamera *const *camlist;
1734 camlist = dt_iop_lensfun_db->GetCameras();
1736 if(IS_NULL_PTR(camlist)) return;
1737 camera_menu_fill(self, camlist);
1738
1739 dt_gui_menu_popup(GTK_MENU(g->camera_menu), button, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH);
1740}
1741
1742static void camera_autosearch_clicked(GtkWidget *button, gpointer user_data)
1743{
1744 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1746 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
1748 char make[200], model[200];
1749 const gchar *txt = (const gchar *)((dt_iop_lensfun_params_t *)self->default_params)->camera;
1750
1751 (void)button;
1752
1753 if(txt[0] == '\0')
1754 {
1755 const lfCamera *const *camlist;
1757 camlist = dt_iop_lensfun_db->GetCameras();
1759 if(IS_NULL_PTR(camlist)) return;
1760 camera_menu_fill(self, camlist);
1761 }
1762 else
1763 {
1764 make[0] = '\0';
1765 parse_model(txt, model, sizeof(model));
1767 const lfCamera **camlist = dt_iop_lensfun_db->FindCamerasExt(make, model, 0);
1769 if(IS_NULL_PTR(camlist)) return;
1770 camera_menu_fill(self, camlist);
1771 lf_free(camlist);
1772 }
1773
1774 dt_gui_menu_popup(GTK_MENU(g->camera_menu), button, GDK_GRAVITY_SOUTH_EAST, GDK_GRAVITY_NORTH_EAST);
1775}
1776
1777/* -- end camera -- */
1778
1780{
1782 const char *text = dt_bauhaus_combobox_get_text(widget);
1783 if(text) (void)sscanf(text, "%f", &p->focal);
1784 p->modified = 1;
1786}
1787
1789{
1791 const char *text = dt_bauhaus_combobox_get_text(widget);
1792 if(text) (void)sscanf(text, "%f", &p->aperture);
1793 p->modified = 1;
1795}
1796
1798{
1800 const char *text = dt_bauhaus_combobox_get_text(widget);
1801 if(text) (void)sscanf(text, "%f", &p->distance);
1802 p->modified = 1;
1804}
1805
1806static void delete_children(GtkWidget *widget, gpointer data)
1807{
1808 (void)data;
1809 gtk_widget_destroy(widget);
1810}
1811
1812static void lens_set(dt_iop_module_t *self, const lfLens *lens)
1813{
1816
1817 gchar *fm;
1818 const char *maker, *model;
1819 unsigned i;
1820 gdouble focal_values[]
1821 = { -INFINITY, 4.5, 8, 10, 12, 14, 15, 16, 17, 18, 20, 24, 28, 30, 31, 35,
1822 38, 40, 43, 45, 50, 55, 60, 70, 75, 77, 80, 85, 90, 100, 105, 110,
1823 120, 135, 150, 200, 210, 240, 250, 300, 400, 500, 600, 800, 1000, INFINITY };
1824 gdouble aperture_values[]
1825 = { -INFINITY, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.4, 1.8, 2, 2.2, 2.5, 2.8, 3.2, 3.4, 4, 4.5, 5.0,
1826 5.6, 6.3, 7.1, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 29, 32, 38, INFINITY };
1827
1828 if(!lens)
1829 {
1830 gtk_widget_set_sensitive(GTK_WIDGET(g->modflags), FALSE);
1831 gtk_widget_set_sensitive(GTK_WIDGET(g->target_geom), FALSE);
1832 gtk_widget_set_sensitive(GTK_WIDGET(g->scale), FALSE);
1833 gtk_widget_set_sensitive(GTK_WIDGET(g->reverse), FALSE);
1834 gtk_widget_set_sensitive(GTK_WIDGET(g->tca_r), FALSE);
1835 gtk_widget_set_sensitive(GTK_WIDGET(g->tca_b), FALSE);
1836 gtk_widget_set_sensitive(GTK_WIDGET(g->message), FALSE);
1837
1838 g->trouble = TRUE;
1839 return;
1840 }
1841 else
1842 {
1843 // no longer in trouble
1844 gtk_widget_set_sensitive(GTK_WIDGET(g->modflags), TRUE);
1845 gtk_widget_set_sensitive(GTK_WIDGET(g->target_geom), TRUE);
1846 gtk_widget_set_sensitive(GTK_WIDGET(g->scale), TRUE);
1847 gtk_widget_set_sensitive(GTK_WIDGET(g->reverse), TRUE);
1848 gtk_widget_set_sensitive(GTK_WIDGET(g->tca_r), TRUE);
1849 gtk_widget_set_sensitive(GTK_WIDGET(g->tca_b), TRUE);
1850 gtk_widget_set_sensitive(GTK_WIDGET(g->message), TRUE);
1851
1852 g->trouble = FALSE;
1853 }
1854
1855 maker = lf_mlstr_get(lens->Maker);
1856 model = lf_mlstr_get(lens->Model);
1857
1858 g_strlcpy(p->lens, lens->Model, sizeof(p->lens));
1859
1860 if(model)
1861 {
1862 if(maker)
1863 fm = g_strdup_printf("%s, %s", maker, model);
1864 else
1865 fm = g_strdup_printf("%s", model);
1866 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->lens_model))), fm);
1867 dt_free(fm);
1868 }
1869
1870 char focal[100], aperture[100], mounts[200];
1871
1872 if(lens->MinFocal < lens->MaxFocal)
1873 snprintf(focal, sizeof(focal), "%g-%gmm", lens->MinFocal, lens->MaxFocal);
1874 else
1875 snprintf(focal, sizeof(focal), "%gmm", lens->MinFocal);
1876 if(lens->MinAperture < lens->MaxAperture)
1877 snprintf(aperture, sizeof(aperture), "%g-%g", lens->MinAperture, lens->MaxAperture);
1878 else
1879 snprintf(aperture, sizeof(aperture), "%g", lens->MinAperture);
1880
1881 mounts[0] = 0;
1882#ifdef LF_0395
1883 const char* const* mount_names = lens->GetMountNames();
1884 i = 0;
1885 while (mount_names && *mount_names) {
1886 if(i > 0) g_strlcat(mounts, ", ", sizeof(mounts));
1887 g_strlcat(mounts, *mount_names, sizeof(mounts));
1888 i++;
1889 mount_names++;
1890 }
1891#else
1892 if(lens->Mounts)
1893 for(i = 0; lens->Mounts[i]; i++)
1894 {
1895 if(i > 0) g_strlcat(mounts, ", ", sizeof(mounts));
1896 g_strlcat(mounts, lens->Mounts[i], sizeof(mounts));
1897 }
1898#endif
1899 fm = g_strdup_printf(_("maker:\t\t%s\n"
1900 "model:\t\t%s\n"
1901 "focal range:\t%s\n"
1902 "aperture:\t%s\n"
1903 "crop factor:\t%.1f\n"
1904 "type:\t\t%s\n"
1905 "mounts:\t%s"),
1906 maker ? maker : "?", model ? model : "?", focal, aperture,
1907#ifdef LF_0395
1908 g->camera->CropFactor,
1909#else
1910 lens->CropFactor,
1911#endif
1912 lfLens::GetLensTypeDesc(lens->Type, NULL), mounts);
1913
1914 gtk_widget_set_tooltip_text(GTK_WIDGET(g->lens_model), fm);
1915 dt_free(fm);
1916
1917 /* Create the focal/aperture/distance combo boxes */
1918 gtk_container_foreach(GTK_CONTAINER(g->lens_param_box), delete_children, NULL);
1919
1920 int ffi = 1, fli = -1;
1921 for(i = 1; i < sizeof(focal_values) / sizeof(gdouble) - 1; i++)
1922 {
1923 if(focal_values[i] < lens->MinFocal) ffi = i + 1;
1924 if(focal_values[i] > lens->MaxFocal && fli == -1) fli = i;
1925 }
1926 if(focal_values[ffi] > lens->MinFocal)
1927 {
1928 focal_values[ffi - 1] = lens->MinFocal;
1929 ffi--;
1930 }
1931 if(lens->MaxFocal == 0 || fli < 0) fli = sizeof(focal_values) / sizeof(gdouble) - 2;
1932 if(focal_values[fli + 1] < lens->MaxFocal)
1933 {
1934 focal_values[fli + 1] = lens->MaxFocal;
1935 ffi++;
1936 }
1937 if(fli < ffi) fli = ffi + 1;
1938
1939 GtkWidget *w;
1940 char txt[30];
1941
1942 // focal length
1944 dt_bauhaus_widget_set_label(w, N_("mm"));
1945 gtk_widget_set_tooltip_text(w, _("focal length (mm)"));
1946 snprintf(txt, sizeof(txt), "%.*f", precision(p->focal, 10.0), p->focal);
1948 for(int k = 0; k < fli - ffi; k++)
1949 {
1950 snprintf(txt, sizeof(txt), "%.*f", precision(focal_values[ffi + k], 10.0), focal_values[ffi + k]);
1952 }
1953 g_signal_connect(G_OBJECT(w), "value-changed", G_CALLBACK(lens_comboentry_focal_update), self);
1954 gtk_box_pack_start(GTK_BOX(g->lens_param_box), w, TRUE, TRUE, 0);
1956 g->cbe[0] = w;
1957
1958 // f-stop
1959 ffi = 1, fli = sizeof(aperture_values) / sizeof(gdouble) - 1;
1960 for(i = 1; i < sizeof(aperture_values) / sizeof(gdouble) - 1; i++)
1961 if(aperture_values[i] < lens->MinAperture) ffi = i + 1;
1962 if(aperture_values[ffi] > lens->MinAperture)
1963 {
1964 aperture_values[ffi - 1] = lens->MinAperture;
1965 ffi--;
1966 }
1967
1969 dt_bauhaus_widget_set_label(w, N_("f"));
1970 gtk_widget_set_tooltip_text(w, _("f-number (aperture)"));
1971 snprintf(txt, sizeof(txt), "%.*f", precision(p->aperture, 10.0), p->aperture);
1973 for(int k = 0; k < fli - ffi; k++)
1974 {
1975 snprintf(txt, sizeof(txt), "%.*f", precision(aperture_values[ffi + k], 10.0), aperture_values[ffi + k]);
1977 }
1978 g_signal_connect(G_OBJECT(w), "value-changed", G_CALLBACK(lens_comboentry_aperture_update), self);
1979 gtk_box_pack_start(GTK_BOX(g->lens_param_box), w, TRUE, TRUE, 0);
1981 g->cbe[1] = w;
1982
1984 dt_bauhaus_widget_set_label(w, N_("d"));
1985 gtk_widget_set_tooltip_text(w, _("distance to subject"));
1986 snprintf(txt, sizeof(txt), "%.*f", precision(p->distance, 10.0), p->distance);
1988 float val = 0.25f;
1989 for(int k = 0; k < 25; k++)
1990 {
1991 if(val > 1000.0f) val = 1000.0f;
1992 snprintf(txt, sizeof(txt), "%.*f", precision(val, 10.0), val);
1994 if(val >= 1000.0f) break;
1995 val *= sqrtf(2.0f);
1996 }
1997 g_signal_connect(G_OBJECT(w), "value-changed", G_CALLBACK(lens_comboentry_distance_update), self);
1998 gtk_box_pack_start(GTK_BOX(g->lens_param_box), w, TRUE, TRUE, 0);
2000 g->cbe[2] = w;
2001
2002 gtk_widget_show_all(g->lens_param_box);
2003}
2004
2005static void lens_menu_select(GtkMenuItem *menuitem, gpointer user_data)
2006{
2007 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2010 lens_set(self, (lfLens *)g_object_get_data(G_OBJECT(menuitem), "lfLens"));
2011 if(darktable.gui->reset) return;
2012 p->modified = 1;
2013 const float scale = get_autoscale(self, p, g->camera);
2014 dt_bauhaus_slider_set(g->scale, scale);
2016}
2017
2018static void lens_menu_fill(dt_iop_module_t *self, const lfLens *const *lenslist)
2019{
2021 unsigned i;
2022 GPtrArray *makers, *submenus;
2023
2024 if(g->lens_menu)
2025 {
2026 gtk_widget_destroy(GTK_WIDGET(g->lens_menu));
2027 g->lens_menu = NULL;
2028 }
2029
2030 /* Count all existing lens makers and create a sorted list */
2031 makers = g_ptr_array_new();
2032 submenus = g_ptr_array_new();
2033 for(i = 0; lenslist[i]; i++)
2034 {
2035 GtkWidget *submenu, *item;
2036 const char *m = lf_mlstr_get(lenslist[i]->Maker);
2037 int idx = ptr_array_find_sorted(makers, m, (GCompareFunc)g_utf8_collate);
2038 if(idx < 0)
2039 {
2040 /* No such maker yet, insert it into the array */
2041 idx = ptr_array_insert_sorted(makers, m, (GCompareFunc)g_utf8_collate);
2042 /* Create a submenu for lenses by this maker */
2043 submenu = gtk_menu_new();
2044 ptr_array_insert_index(submenus, submenu, idx);
2045 }
2046
2047 submenu = (GtkWidget *)g_ptr_array_index(submenus, idx);
2048 /* Append current lens name to the submenu */
2049 item = gtk_menu_item_new_with_label(lf_mlstr_get(lenslist[i]->Model));
2050 gtk_widget_show(item);
2051 g_object_set_data(G_OBJECT(item), "lfLens", (void *)lenslist[i]);
2052 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(lens_menu_select), self);
2053 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
2054 }
2055
2056 g->lens_menu = GTK_MENU(gtk_menu_new());
2057 for(i = 0; i < makers->len; i++)
2058 {
2059 GtkWidget *item = gtk_menu_item_new_with_label((const gchar *)g_ptr_array_index(makers, i));
2060 gtk_widget_show(item);
2061 gtk_menu_shell_append(GTK_MENU_SHELL(g->lens_menu), item);
2062 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), (GtkWidget *)g_ptr_array_index(submenus, i));
2063 }
2064
2065 g_ptr_array_free(submenus, TRUE);
2066 g_ptr_array_free(makers, TRUE);
2067}
2068
2069static void lens_menusearch_clicked(GtkWidget *button, gpointer user_data)
2070{
2071 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2073 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
2075 const lfLens **lenslist;
2076
2077 (void)button;
2078
2080 lenslist = dt_iop_lensfun_db->FindLenses(g->camera, NULL, NULL, LF_SEARCH_SORT_AND_UNIQUIFY);
2082 if(IS_NULL_PTR(lenslist)) return;
2083 lens_menu_fill(self, lenslist);
2084 lf_free(lenslist);
2085
2086 dt_gui_menu_popup(GTK_MENU(g->lens_menu), button, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH);
2087}
2088
2089static void lens_autosearch_clicked(GtkWidget *button, gpointer user_data)
2090{
2091 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2093 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
2095 const lfLens **lenslist;
2096 char model[200];
2097 const gchar *txt = ((dt_iop_lensfun_params_t *)self->default_params)->lens;
2098
2099 (void)button;
2100
2101 parse_model(txt, model, sizeof(model));
2103 lenslist = dt_iop_lensfun_db->FindLenses(g->camera, NULL,
2106 if(IS_NULL_PTR(lenslist)) return;
2107 lens_menu_fill(self, lenslist);
2108 lf_free(lenslist);
2109
2110 dt_gui_menu_popup(GTK_MENU(g->lens_menu), button, GDK_GRAVITY_SOUTH_EAST, GDK_GRAVITY_NORTH_EAST);
2111}
2112
2113/* -- end lens -- */
2114
2115static void target_geometry_changed(GtkWidget *widget, gpointer user_data)
2116{
2117 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2119
2120 int pos = dt_bauhaus_combobox_get(widget);
2121 p->target_geom = (lfLensType)(pos + LF_UNKNOWN + 1);
2122 p->modified = 1;
2124}
2125
2126static void modflags_changed(GtkWidget *widget, gpointer user_data)
2127{
2128 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2129 if(darktable.gui->reset) return;
2132 int pos = dt_bauhaus_combobox_get(widget);
2133 for(GList *modifiers = g->modifiers; modifiers; modifiers = g_list_next(modifiers))
2134 {
2136 if(mm->pos == pos)
2137 {
2138 p->modify_flags = (p->modify_flags & ~LENSFUN_MODFLAG_MASK) | mm->modflag;
2139 p->modified = 1;
2141 break;
2142 }
2143 }
2144}
2145
2146void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
2147{
2150 const gboolean raw_monochrome = dt_image_is_monochrome(&self->dev->image_storage);
2151 gtk_widget_set_visible(g->tca_override, !raw_monochrome);
2152 // update gui to show/hide tca sliders if tca_override was changed
2153 if(IS_NULL_PTR(w) || w == g->tca_override)
2154 {
2155 // show tca sliders only iff tca_overwrite is set
2156 gtk_widget_set_visible(g->tca_r, p->tca_override && !raw_monochrome);
2157 gtk_widget_set_visible(g->tca_b, p->tca_override && !raw_monochrome);
2158 }
2159
2160 if(w)
2161 {
2162 // user did modify something with some widget
2163 p->modified = 1;
2164 }
2165}
2166
2167
2168static float get_autoscale(dt_iop_module_t *self, dt_iop_lensfun_params_t *p, const lfCamera *camera)
2169{
2171 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
2172 float scale = 1.0;
2173 if(p->lens[0] != '\0')
2174 {
2176 const lfLens **lenslist
2177 = dt_iop_lensfun_db->FindLenses(camera, NULL, p->lens, 0);
2178 if(lenslist)
2179 {
2180 const dt_image_t *img = &(self->dev->image_storage);
2181
2182 // FIXME: get those from rawprepare IOP somehow !!!
2183 const int iwd = img->width - img->crop_x - img->crop_width,
2184 iht = img->height - img->crop_y - img->crop_height;
2185
2186 // create dummy modifier
2187#if defined(__GNUC__) && (__GNUC__ > 7)
2188 const dt_iop_lensfun_data_t d =
2189 {
2190 .lens = (lfLens *)lenslist[0],
2191 .modify_flags = p->modify_flags,
2192 .inverse = p->inverse,
2193 .scale = 1.0f,
2194 .crop = p->crop,
2195 .focal = p->focal,
2196 .aperture = p->aperture,
2197 .distance = p->distance,
2198 .target_geom = p->target_geom,
2199 .custom_tca = { .Model = LF_TCA_MODEL_NONE }
2200 };
2201#else
2202 // prior to GCC 8.x the / .custom_tca = { .Model = ??? } / was not supported:
2203 // sorry, unimplemented: non-trivial designated initializers not supported
2204 // ?? This code can be removed when GCC-7 is not used anymore.
2205
2207 d.lens = (lfLens *)lenslist[0];
2208 d.modify_flags = p->modify_flags;
2209 d.inverse = p->inverse;
2210 d.scale = 1.0f;
2211 d.crop = p->crop;
2212 d.focal = p->focal;
2213 d.aperture = p->aperture;
2214 d.distance = p->distance;
2215 d.target_geom = p->target_geom;
2216 d.custom_tca.Model = LF_TCA_MODEL_NONE;
2217#endif
2218
2219 lfModifier *modifier = get_modifier(NULL, iwd, iht, &d, LF_MODIFY_ALL, FALSE);
2220
2221 scale = modifier->GetAutoScale(p->inverse);
2222 delete modifier;
2223 }
2224 lf_free(lenslist);
2226 }
2227 return scale;
2228}
2229
2230static void autoscale_pressed(GtkWidget *button, gpointer user_data)
2231{
2232 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2235 const float scale = get_autoscale(self, p, g->camera);
2236 p->modified = 1;
2237 dt_bauhaus_slider_set(g->scale, scale);
2239}
2240
2241static void corrections_done(gpointer instance, gpointer user_data)
2242{
2243 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2245 if(darktable.gui->reset) return;
2246
2248 const int corrections_done = g->corrections_done;
2250
2251 const char empty_message[] = "";
2252 char *message = (char *)empty_message;
2253 for(GList *modifiers = g->modifiers; modifiers && self->enabled; modifiers = g_list_next(modifiers))
2254 {
2256 if(mm->modflag == corrections_done)
2257 {
2258 message = mm->name;
2259 break;
2260 }
2261 }
2262
2263 ++darktable.gui->reset;
2264 gtk_label_set_text(g->message, message);
2265 gtk_widget_set_tooltip_text(GTK_WIDGET(g->message), message);
2266 --darktable.gui->reset;
2267}
2268
2269void gui_init(struct dt_iop_module_t *self)
2270{
2272
2273 g->camera = NULL;
2274 g->camera_menu = NULL;
2275 g->lens_menu = NULL;
2276 g->modifiers = NULL;
2277
2278 dt_iop_gui_enter_critical_section(self); // not actually needed, we're the only one with a ref to this instance
2279 g->corrections_done = -1;
2281
2282 // initialize modflags options
2283 int pos = -1;
2284 dt_iop_lensfun_modifier_t *modifier;
2285 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2286 dt_utf8_strlcpy(modifier->name, _("none"), sizeof(modifier->name));
2287 g->modifiers = g_list_append(g->modifiers, modifier);
2288 modifier->modflag = LENSFUN_MODFLAG_NONE;
2289 modifier->pos = ++pos;
2290
2291 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2292 dt_utf8_strlcpy(modifier->name, _("all"), sizeof(modifier->name));
2293 g->modifiers = g_list_append(g->modifiers, modifier);
2294 modifier->modflag = LENSFUN_MODFLAG_ALL;
2295 modifier->pos = ++pos;
2296
2297 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2298 dt_utf8_strlcpy(modifier->name, _("distortion & TCA"), sizeof(modifier->name));
2299 g->modifiers = g_list_append(g->modifiers, modifier);
2301 modifier->pos = ++pos;
2302
2303 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2304 dt_utf8_strlcpy(modifier->name, _("distortion & vignetting"), sizeof(modifier->name));
2305 g->modifiers = g_list_append(g->modifiers, modifier);
2307 modifier->pos = ++pos;
2308
2309 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2310 dt_utf8_strlcpy(modifier->name, _("TCA & vignetting"), sizeof(modifier->name));
2311 g->modifiers = g_list_append(g->modifiers, modifier);
2313 modifier->pos = ++pos;
2314
2315 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2316 dt_utf8_strlcpy(modifier->name, _("only distortion"), sizeof(modifier->name));
2317 g->modifiers = g_list_append(g->modifiers, modifier);
2318 modifier->modflag = LENSFUN_MODFLAG_DIST;
2319 modifier->pos = ++pos;
2320
2321 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2322 dt_utf8_strlcpy(modifier->name, _("only TCA"), sizeof(modifier->name));
2323 g->modifiers = g_list_append(g->modifiers, modifier);
2324 modifier->modflag = LENSFUN_MODFLAG_TCA;
2325 modifier->pos = ++pos;
2326
2327 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2328 dt_utf8_strlcpy(modifier->name, _("only vignetting"), sizeof(modifier->name));
2329 g->modifiers = g_list_append(g->modifiers, modifier);
2330 modifier->modflag = LENSFUN_MODFLAG_VIGN;
2331 modifier->pos = ++pos;
2332
2333 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
2334 gtk_widget_set_name(self->widget, "lens-module");
2335
2336 // camera selector
2337 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2338 g->camera_model = dt_iop_button_new(self, N_("camera model"),
2339 G_CALLBACK(camera_menusearch_clicked), FALSE, 0, (GdkModifierType)0,
2340 NULL, 0, hbox);
2341 g->find_camera_button = dt_iop_button_new(self, N_("find camera"),
2342 G_CALLBACK(camera_autosearch_clicked), FALSE, 0, (GdkModifierType)0,
2344 dt_gui_add_class(g->find_camera_button, "dt_big_btn_canvas");
2345 gtk_box_pack_start(GTK_BOX(hbox), g->find_camera_button, FALSE, FALSE, 0);
2346 gtk_box_pack_start(GTK_BOX(self->widget), hbox, TRUE, TRUE, 0);
2347
2348 // lens selector
2349 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2350 g->lens_model = dt_iop_button_new(self, N_("lens model"),
2351 G_CALLBACK(lens_menusearch_clicked), FALSE, 0, (GdkModifierType)0,
2352 NULL, 0, hbox);
2353 g->find_lens_button = dt_iop_button_new(self, N_("find lens"),
2354 G_CALLBACK(lens_autosearch_clicked), FALSE, 0, (GdkModifierType)0,
2356 dt_gui_add_class(g->find_lens_button, "dt_big_btn_canvas");
2357 gtk_box_pack_start(GTK_BOX(hbox), g->find_lens_button, FALSE, FALSE, 0);
2358 gtk_box_pack_start(GTK_BOX(self->widget), hbox, TRUE, TRUE, 0);
2359
2360 // lens properties
2361 g->lens_param_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2362 gtk_box_pack_start(GTK_BOX(self->widget), g->lens_param_box, TRUE, TRUE, 0);
2363
2364#if 0
2365 // if unambiguous info is there, use it.
2366 if(self->dev->image_storage.exif_lens[0] != '\0')
2367 {
2368 char make [200], model [200];
2369 const gchar *txt = gtk_entry_get_text(GTK_ENTRY(g->lens_model));
2370 parse_maker_model (txt, make, sizeof (make), model, sizeof (model));
2372 const lfLens **lenslist = lf_db_find_lenses_hd (dt_iop_lensfun_db, g->camera,
2373 make [0] ? make : NULL,
2374 model [0] ? model : NULL, 0);
2375 if(lenslist) lens_set (self, lenslist[0]);
2376 lf_free (lenslist);
2378 }
2379#endif
2380
2381 // selector for correction type (modflags): one or more out of distortion, TCA, vignetting
2383 dt_bauhaus_widget_set_label(g->modflags, N_("corrections"));
2384 gtk_box_pack_start(GTK_BOX(self->widget), g->modflags, TRUE, TRUE, 0);
2385 gtk_widget_set_tooltip_text(g->modflags, _("which corrections to apply"));
2386 GList *l = g->modifiers;
2387 while(l)
2388 {
2389 modifier = (dt_iop_lensfun_modifier_t *)l->data;
2390 dt_bauhaus_combobox_add(g->modflags, modifier->name);
2391 l = g_list_next(l);
2392 }
2393 dt_bauhaus_combobox_set(g->modflags, 0);
2394 g_signal_connect(G_OBJECT(g->modflags), "value-changed", G_CALLBACK(modflags_changed), (gpointer)self);
2395
2396 // target geometry
2398 dt_bauhaus_widget_set_label(g->target_geom, N_("geometry"));
2399 gtk_box_pack_start(GTK_BOX(self->widget), g->target_geom, TRUE, TRUE, 0);
2400 gtk_widget_set_tooltip_text(g->target_geom, _("target geometry"));
2401 dt_bauhaus_combobox_add(g->target_geom, _("rectilinear"));
2402 dt_bauhaus_combobox_add(g->target_geom, _("fish-eye"));
2403 dt_bauhaus_combobox_add(g->target_geom, _("panoramic"));
2404 dt_bauhaus_combobox_add(g->target_geom, _("equirectangular"));
2405#if LF_VERSION >= ((0 << 24) | (2 << 16) | (6 << 8) | 0)
2406 dt_bauhaus_combobox_add(g->target_geom, _("orthographic"));
2407 dt_bauhaus_combobox_add(g->target_geom, _("stereographic"));
2408 dt_bauhaus_combobox_add(g->target_geom, _("equisolid angle"));
2409 dt_bauhaus_combobox_add(g->target_geom, _("thoby fish-eye"));
2410#endif
2411 g_signal_connect(G_OBJECT(g->target_geom), "value-changed", G_CALLBACK(target_geometry_changed),
2412 (gpointer)self);
2413
2414 // scale
2415 g->scale = dt_bauhaus_slider_from_params(self, N_("scale"));
2418 g_signal_connect(G_OBJECT(g->scale), "quad-pressed", G_CALLBACK(autoscale_pressed), self);
2419 gtk_widget_set_tooltip_text(g->scale, _("auto scale"));
2420
2421 // reverse direction
2422 g->reverse = dt_bauhaus_combobox_from_params(self, "inverse");
2423 dt_bauhaus_combobox_add(g->reverse, _("correct"));
2424 dt_bauhaus_combobox_add(g->reverse, _("distort"));
2425 gtk_widget_set_tooltip_text(g->reverse, _("correct distortions or apply them"));
2426
2427 g->tca_override = dt_bauhaus_toggle_from_params(self, "tca_override");
2428
2429 // override linear tca (if not 1.0):
2430 g->tca_r = dt_bauhaus_slider_from_params(self, "tca_r");
2432 gtk_widget_set_tooltip_text(g->tca_r, _("Transversal Chromatic Aberration red"));
2433
2434 g->tca_b = dt_bauhaus_slider_from_params(self, "tca_b");
2436 gtk_widget_set_tooltip_text(g->tca_b, _("Transversal Chromatic Aberration blue"));
2437
2438 // message box to inform user what corrections have been done. this is useful as depending on lensfuns
2439 // profile only some of the lens flaws can be corrected
2440 GtkBox *hbox1 = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
2441 GtkWidget *label = gtk_label_new(_("corrections done: "));
2442 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE);
2443 gtk_widget_set_tooltip_text(label, _("which corrections have actually been done"));
2444 gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
2445 g->message = GTK_LABEL(gtk_label_new("")); // This gets filled in by process
2446 gtk_label_set_ellipsize(GTK_LABEL(g->message), PANGO_ELLIPSIZE_MIDDLE);
2447 gtk_box_pack_start(GTK_BOX(hbox1), GTK_WIDGET(g->message), FALSE, FALSE, 0);
2448 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox1), TRUE, TRUE, 0);
2449
2450 /* add signal handler for preview pipe finish to update message on corrections done */
2452 G_CALLBACK(corrections_done), self);
2453}
2454
2455void gui_update(struct dt_iop_module_t *self)
2456{
2457 // let gui elements reflect params
2460
2461 if(p->modified == 0)
2462 {
2463 /*
2464 * user did not modify anything in gui after autodetection - let's
2465 * use current default_params as params - for presets and mass-export
2466 */
2467 memcpy(self->params, self->default_params, sizeof(dt_iop_lensfun_params_t));
2468 }
2469
2471 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
2472 // these are the wrong (untranslated) strings in general but that's ok, they will be overwritten further
2473 // down
2474 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->camera_model))), p->camera);
2475 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->lens_model))), p->lens);
2476 gtk_widget_set_tooltip_text(g->camera_model, "");
2477 gtk_widget_set_tooltip_text(g->lens_model, "");
2478
2479 int modflag = p->modify_flags & LENSFUN_MODFLAG_MASK;
2480 for(GList *modifiers = g->modifiers; modifiers; modifiers = g_list_next(modifiers))
2481 {
2483 if(mm->modflag == modflag)
2484 {
2485 dt_bauhaus_combobox_set(g->modflags, mm->pos);
2486 break;
2487 }
2488 }
2489
2490 dt_bauhaus_combobox_set(g->target_geom, p->target_geom - LF_UNKNOWN - 1);
2491 dt_bauhaus_combobox_set(g->reverse, p->inverse);
2492 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->tca_override), p->tca_override);
2493 const lfCamera **cam = NULL;
2494 g->camera = NULL;
2495 if(p->camera[0])
2496 {
2498 cam = dt_iop_lensfun_db->FindCamerasExt(NULL, p->camera, 0);
2500 if(cam)
2501 camera_set(self, cam[0]);
2502 else
2503 camera_set(self, NULL);
2504 lf_free(cam);
2505 }
2506 if(g->camera && p->lens[0])
2507 {
2508 char model[200];
2509 parse_model(p->lens, model, sizeof(model));
2511 const lfLens **lenslist = dt_iop_lensfun_db->FindLenses(g->camera, NULL,
2512 model[0] ? model : NULL, 0);
2513 if(lenslist)
2514 lens_set(self, lenslist[0]);
2515 else
2516 lens_set(self, NULL);
2517 lf_free(lenslist);
2519 }
2520 else
2521 {
2523 lens_set(self, NULL);
2525 }
2526
2527 gui_changed(self, NULL, NULL);
2528}
2529
2531{
2533
2535
2536 while(g->modifiers)
2537 {
2538 dt_free(g->modifiers->data);
2539 g->modifiers = g_list_delete_link(g->modifiers, g->modifiers);
2540 }
2541
2543}
2544
2545}
2546
2547// clang-format off
2548// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2549// vim: shiftwidth=2 expandtab tabstop=2 cindent
2550// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2551// 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
#define m
Definition basecurve.c:278
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
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_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
void dt_bauhaus_widget_set_quad_paint(GtkWidget *widget, dt_bauhaus_quad_paint_f f, int paint_flags, void *paint_data)
Definition bauhaus.c:1702
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
@ IOP_CS_RGB
const dt_colormatrix_t dt_aligned_pixel_t out
dt_store_simd_aligned(out, dt_mat3x4_mul_vec4(vin, dt_colormatrix_row_to_simd(matrix, 0), dt_colormatrix_row_to_simd(matrix, 1), dt_colormatrix_row_to_simd(matrix, 2)))
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
gboolean dt_image_is_monochrome(const dt_image_t *img)
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
#define STR(x)
Definition darktable.h:170
#define dt_free_align(ptr)
Definition darktable.h:481
static void * dt_calloc_align(size_t size)
Definition darktable.h:488
@ DT_DEBUG_OPENCL
Definition darktable.h:722
#define DT_ALIGNED_ARRAY
Definition darktable.h:388
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:433
#define __OMP_FOR__(...)
Definition darktable.h:261
#define dt_free(ptr)
Definition darktable.h:456
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define __OMP_PARALLEL_FOR_CPP__(...)
Definition darktable.h:265
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
#define dt_get_perthread(buf, padsize)
Definition darktable.h:1035
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
Definition darktable.h:1030
#define DT_PIXEL_SIMD_CHANNELS
Definition darktable.h:638
#define PATH_MAX
Definition darktable.h:1062
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
#define BLUE
#define RED
#define GREEN
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:41
gboolean dt_dev_pixelpipe_has_preview_output(const dt_develop_t *dev, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi)
Definition develop.c:367
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:118
void dtgtk_cairo_paint_refresh(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_solid_arrow(cairo_t *cr, gint x, int y, gint w, gint h, gint flags, void *data)
@ CPF_DIRECTION_DOWN
Definition dtgtk/paint.h:62
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
void dt_loc_get_datadir(char *datadir, size_t bufsize)
void dt_gui_menu_popup(GtkMenu *menu, GtkWidget *button, GdkGravity widget_anchor, GdkGravity menu_anchor)
Definition gtk.c:2953
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
Definition gtk.c:133
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_GUI_MODULE(x)
static void dt_iop_image_copy_by_size(float *const __restrict__ out, const float *const __restrict__ in, const size_t width, const size_t height, const size_t ch)
Definition imagebuf.h:87
void dt_iop_compute_module_hash(dt_iop_module_t *module, GList *masks)
Definition imageop.c:1890
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
#define IOP_GUI_FREE
Definition imageop.h:602
static void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module) ACQUIRE(&module -> gui_lock)
Definition imageop.h:413
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:169
@ IOP_FLAGS_UNSAFE_COPY
Definition imageop.h:177
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:171
static void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module) RELEASE(&module -> gui_lock)
Definition imageop.h:419
@ IOP_GROUP_REPAIR
Definition imageop.h:140
#define IOP_GUI_ALLOC(module)
Definition imageop.h:599
@ IOP_TAG_DISTORT
Definition imageop.h:151
GtkWidget * dt_iop_button_new(dt_iop_module_t *self, const gchar *label, GCallback callback, gboolean local, guint accel_key, GdkModifierType mods, DTGTKCairoPaintIconFunc paint, gint paintflags, GtkWidget *box)
GtkWidget * dt_bauhaus_toggle_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
Definition imageop_gui.c:77
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
void *const ovoid
const struct dt_interpolation * dt_interpolation_new(enum dt_interpolation_type type)
__DT_CLONE_TARGETS__ float dt_interpolation_compute_sample(const struct dt_interpolation *itor, const float *in, const float x, const float y, const int width, const int height, const int samplestride, const int linestride)
@ DT_INTERPOLATION_BICUBIC
@ DT_INTERPOLATION_BILINEAR
@ DT_INTERPOLATION_MITCHELL
@ DT_INTERPOLATION_USERPREF_WARP
const char * maker
const char * model
static const float x
#define LF_SEARCH_SORT_AND_UNIQUIFY
Definition lens.cc:103
int operation_tags()
Definition lens.cc:219
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 lens.cc:968
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 lens.cc:1164
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 lens.cc:999
const char ** description(struct dt_iop_module_t *self)
Definition lens.cc:204
int default_group()
Definition lens.cc:214
static void _lens_fill_vignette_row(float *const buf, const int width, const int ch)
Definition lens.cc:419
static int ptr_array_find_sorted(const GPtrArray *array, const void *item, GCompareFunc compare)
Definition lens.cc:1555
static void lens_set(dt_iop_module_t *self, const lfLens *lens)
Definition lens.cc:1812
void reload_defaults(dt_iop_module_t *module)
Definition lens.cc:1363
static void lens_comboentry_distance_update(GtkWidget *widget, dt_iop_module_t *self)
Definition lens.cc:1797
static __DT_CLONE_TARGETS__ lfModifier * get_modifier(int *mods_done, int w, int h, const dt_iop_lensfun_data_t *d, int mods_filter, gboolean force_inverse)
Definition lens.cc:388
static char * _lens_sanitize(const char *orig_lens)
Definition lens.cc:354
static void lens_autosearch_clicked(GtkWidget *button, gpointer user_data)
Definition lens.cc:2089
static void autoscale_pressed(GtkWidget *button, gpointer user_data)
Definition lens.cc:2230
__DT_CLONE_TARGETS__ int process(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 lens.cc:444
static void camera_menu_select(GtkMenuItem *menuitem, gpointer user_data)
Definition lens.cc:1645
static void camera_set(dt_iop_module_t *self, const lfCamera *cam)
Definition lens.cc:1598
const char * aliases()
Definition lens.cc:199
static void lens_comboentry_focal_update(GtkWidget *widget, dt_iop_module_t *self)
Definition lens.cc:1779
static void camera_menusearch_clicked(GtkWidget *button, gpointer user_data)
Definition lens.cc:1723
static void lens_comboentry_aperture_update(GtkWidget *widget, dt_iop_module_t *self)
Definition lens.cc:1788
dt_iop_lensfun_modflag_t
Definition lens.cc:113
@ LENSFUN_MODFLAG_VIGN
Definition lens.cc:121
@ LENSFUN_MODFLAG_NONE
Definition lens.cc:114
@ LENSFUN_MODFLAG_TCA_VIGN
Definition lens.cc:118
@ LENSFUN_MODFLAG_DIST
Definition lens.cc:119
@ LENSFUN_MODFLAG_DIST_TCA
Definition lens.cc:116
@ LENSFUN_MODFLAG_ALL
Definition lens.cc:115
@ LENSFUN_MODFLAG_TCA
Definition lens.cc:120
@ LENSFUN_MODFLAG_MASK
Definition lens.cc:122
@ LENSFUN_MODFLAG_DIST_VIGN
Definition lens.cc:117
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition lens.cc:1277
const char * name()
Definition lens.cc:194
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 lens.cc:939
static void ptr_array_insert_index(GPtrArray *array, const void *item, int index)
Definition lens.cc:1584
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
Definition lens.cc:2455
static int precision(double x, double adj)
Definition lens.cc:1497
void gui_init(struct dt_iop_module_t *self)
Definition lens.cc:2269
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition lens.cc:2146
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
Definition lens.cc:928
static float get_autoscale(dt_iop_module_t *self, dt_iop_lensfun_params_t *p, const lfCamera *camera)
Definition lens.cc:2168
static void lens_menu_fill(dt_iop_module_t *self, const lfLens *const *lenslist)
Definition lens.cc:2018
void cleanup_global(dt_iop_module_so_t *module)
Definition lens.cc:1478
static void camera_menu_fill(dt_iop_module_t *self, const lfCamera *const *camlist)
Definition lens.cc:1655
static void corrections_done(gpointer instance, gpointer user_data)
Definition lens.cc:2241
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition lens.cc:229
int flags()
Definition lens.cc:224
static void lens_menusearch_clicked(GtkWidget *button, gpointer user_data)
Definition lens.cc:2069
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 *const roi_out, dt_iop_roi_t *roi_in)
Definition lens.cc:1069
void gui_cleanup(struct dt_iop_module_t *self)
Definition lens.cc:2530
static int ptr_array_insert_sorted(GPtrArray *array, const void *item, GCompareFunc compare)
Definition lens.cc:1521
static void lens_menu_select(GtkMenuItem *menuitem, gpointer user_data)
Definition lens.cc:2005
static void target_geometry_changed(GtkWidget *widget, gpointer user_data)
Definition lens.cc:2115
static void parse_model(const char *txt, char *model, size_t sz_model)
Definition lens.cc:1714
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition lens.cc:1283
static void delete_children(GtkWidget *widget, gpointer data)
Definition lens.cc:1806
void init_global(dt_iop_module_so_t *module)
Definition lens.cc:1296
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 lens.cc:677
static void modflags_changed(GtkWidget *widget, gpointer user_data)
Definition lens.cc:2126
static void camera_autosearch_clicked(GtkWidget *button, gpointer user_data)
Definition lens.cc:1742
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 lens.cc:1062
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 lens.cc:234
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2136
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:2544
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2471
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2030
int dt_opencl_write_buffer_to_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
Definition opencl.c:2320
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
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2383
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:39
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:368
@ DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
This signal is raised when develop preview pipe process is finished no param, no returned value.
Definition signal.h:174
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:357
struct _GtkWidget GtkWidget
Definition splash.h:29
const float r
struct dt_gui_gtk_t * gui
Definition darktable.h:775
dt_pthread_mutex_t plugin_threadsafe
Definition darktable.h:793
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_develop_t * develop
Definition darktable.h:770
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
int32_t gui_attached
Definition develop.h:162
dt_image_t image_storage
Definition develop.h:259
GList * forms
Definition develop.h:321
int32_t reset
Definition gtk.h:172
int32_t height
Definition image.h:315
float exif_focus_distance
Definition image.h:290
float exif_aperture
Definition image.h:287
int32_t crop_height
Definition image.h:316
int32_t width
Definition image.h:315
float exif_focal_length
Definition image.h:289
char exif_maker[64]
Definition image.h:292
int32_t crop_y
Definition image.h:316
char exif_lens[128]
Definition image.h:294
int32_t crop_x
Definition image.h:316
char exif_model[64]
Definition image.h:293
int32_t crop_width
Definition image.h:316
float exif_crop
Definition image.h:291
enum dt_interpolation_type id
unsigned int channels
Definition format.h:54
lfLensType target_geom
Definition lens.cc:187
gboolean do_nan_checks
Definition lens.cc:188
gboolean tca_override
Definition lens.cc:189
lfLensCalibTCA custom_tca
Definition lens.cc:190
GtkWidget * modflags
Definition lens.cc:159
GtkWidget * find_camera_button
Definition lens.cc:161
GtkWidget * target_geom
Definition lens.cc:159
GtkWidget * find_lens_button
Definition lens.cc:160
GtkWidget * cbe[3]
Definition lens.cc:154
GtkWidget * lens_param_box
Definition lens.cc:153
GtkWidget * reverse
Definition lens.cc:159
GtkWidget * lens_model
Definition lens.cc:157
GtkWidget * tca_override
Definition lens.cc:159
const lfCamera * camera
Definition lens.cc:152
GtkWidget * camera_model
Definition lens.cc:155
gboolean tca_override
Definition lens.cc:144
lfLensType target_geom
Definition lens.cc:141
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
struct dt_develop_t * dev
Definition imageop.h:296
dt_iop_gui_data_t * gui_data
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:314
gboolean enabled
Definition imageop.h:298
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
size_t dt_utf8_strlcpy(char *dest, const char *src, size_t n)
Definition utility.c:289