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 // The "corrections done" label only reports which corrections apply for the current camera/lens/
668 // params combo -- it doesn't depend on the exact preview ROI, so don't gate it on
669 // dt_dev_pixelpipe_has_preview_output(): that check can transiently reject the very first real
670 // preview-pipe pass right after darkroom entry (preview dimensions not "locked in" yet), leaving
671 // the label permanently blank until some unrelated later event forces another pipe run.
672 if(self->dev->gui_attached && !IS_NULL_PTR(g))
673 {
675 g->corrections_done = (modflags & LENSFUN_MODFLAG_MASK);
677 }
678 return 0;
679}
680
681#ifdef HAVE_OPENCL
682int 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)
683{
684 const dt_iop_roi_t *const roi_in = &piece->roi_in;
685 const dt_iop_roi_t *const roi_out = &piece->roi_out;
689
690 const gboolean raw_monochrome = dt_image_is_monochrome(&self->dev->image_storage);
691 const int used_lf_mask = (raw_monochrome) ? LF_MODIFY_ALL & ~LF_MODIFY_TCA : LF_MODIFY_ALL;
692
693 cl_mem dev_tmpbuf = NULL;
694 cl_mem dev_tmp = NULL;
695 cl_int err = -999;
696
697 float *tmpbuf = NULL;
698 lfModifier *modifier = NULL;
699
700 const int devid = pipe->devid;
701 const int iwidth = roi_in->width;
702 const int iheight = roi_in->height;
703 const int owidth = roi_out->width;
704 const int oheight = roi_out->height;
705 const int roi_in_x = roi_in->x;
706 const int roi_in_y = roi_in->y;
707 const int width = MAX(iwidth, owidth);
708 const int height = MAX(iheight, oheight);
709 const int ch = piece->dsc_in.channels;
710 const int tmpbufwidth = owidth * 2 * 3;
711 const size_t tmpbuflen = d->inverse ? (size_t)oheight * owidth * 2 * 3 * sizeof(float)
712 : MAX((size_t)oheight * owidth * 2 * 3, (size_t)iheight * iwidth * ch)
713 * sizeof(float);
714 const unsigned int pixelformat = ch == 3 ? LF_CR_3(RED, GREEN, BLUE) : LF_CR_4(RED, GREEN, BLUE, UNKNOWN);
715
716 const float orig_w = roi_in->scale * piece->buf_in.width, orig_h = roi_in->scale * piece->buf_in.height;
717
718 size_t origin[] = { 0, 0, 0 };
719 size_t iregion[] = { (size_t)iwidth, (size_t)iheight, 1 };
720 size_t oregion[] = { (size_t)owidth, (size_t)oheight, 1 };
721 size_t isizes[] = { (size_t)ROUNDUPDWD(iwidth, devid), (size_t)ROUNDUPDHT(iheight, devid), 1 };
722 size_t osizes[] = { (size_t)ROUNDUPDWD(owidth, devid), (size_t)ROUNDUPDHT(oheight, devid), 1 };
723
724 int modflags;
725 int ldkernel = -1;
727
728 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f)
729 {
730 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, oregion);
731 if(err != CL_SUCCESS) goto error;
732 return TRUE;
733 }
734
735 switch(interpolation->id)
736 {
738 ldkernel = gd->kernel_lens_distort_bilinear;
739 break;
741 ldkernel = gd->kernel_lens_distort_bicubic;
742 break;
744 ldkernel = gd->kernel_lens_distort_mitchell;
745 break;
746 default:
747 return FALSE;
748 }
749
750 tmpbuf = (float *)dt_pixelpipe_cache_alloc_align_cache(
751 tmpbuflen,
752 pipe->type);
753 if(IS_NULL_PTR(tmpbuf)) goto error;
754
755 dev_tmp = (cl_mem)dt_opencl_alloc_device(devid, width, height, sizeof(float) * 4);
756 if(IS_NULL_PTR(dev_tmp)) goto error;
757
758 dev_tmpbuf = (cl_mem)dt_opencl_alloc_device_buffer(devid, tmpbuflen);
759 if(IS_NULL_PTR(dev_tmpbuf)) goto error;
760
762 modifier = get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, FALSE);
764
765 if(d->inverse)
766 {
767 // reverse direction (useful for renderings)
768 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
769 {
770 __OMP_PARALLEL_FOR_CPP__(firstprivate(modifier, tmpbuf, roi_out, tmpbufwidth))
771 for(int y = 0; y < roi_out->height; y++)
772 {
773 float *pi = tmpbuf + (size_t)y * tmpbufwidth;
774 modifier->ApplySubpixelGeometryDistortion(roi_out->x, roi_out->y + y, roi_out->width, 1, pi);
775 }
776
777
778 /* _blocking_ memory transfer: host tmpbuf buffer -> opencl dev_tmpbuf */
779 err = dt_opencl_write_buffer_to_device(devid, tmpbuf, dev_tmpbuf, 0,
780 (size_t)owidth * oheight * 2 * 3 * sizeof(float), CL_TRUE);
781 if(err != CL_SUCCESS) goto error;
782
783 dt_opencl_set_kernel_arg(devid, ldkernel, 0, sizeof(cl_mem), (void *)&dev_in);
784 dt_opencl_set_kernel_arg(devid, ldkernel, 1, sizeof(cl_mem), (void *)&dev_tmp);
785 dt_opencl_set_kernel_arg(devid, ldkernel, 2, sizeof(int), (void *)&owidth);
786 dt_opencl_set_kernel_arg(devid, ldkernel, 3, sizeof(int), (void *)&oheight);
787 dt_opencl_set_kernel_arg(devid, ldkernel, 4, sizeof(int), (void *)&iwidth);
788 dt_opencl_set_kernel_arg(devid, ldkernel, 5, sizeof(int), (void *)&iheight);
789 dt_opencl_set_kernel_arg(devid, ldkernel, 6, sizeof(int), (void *)&roi_in_x);
790 dt_opencl_set_kernel_arg(devid, ldkernel, 7, sizeof(int), (void *)&roi_in_y);
791 dt_opencl_set_kernel_arg(devid, ldkernel, 8, sizeof(cl_mem), (void *)&dev_tmpbuf);
792 dt_opencl_set_kernel_arg(devid, ldkernel, 9, sizeof(int), (void *)&(d->do_nan_checks));
793 dt_opencl_set_kernel_arg(devid, ldkernel, 10, sizeof(int), (void *)&(raw_monochrome));
794 err = dt_opencl_enqueue_kernel_2d(devid, ldkernel, osizes);
795 if(err != CL_SUCCESS) goto error;
796 }
797 else
798 {
799 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_tmp, origin, origin, oregion);
800 if(err != CL_SUCCESS) goto error;
801 }
802
803 if(modflags & LF_MODIFY_VIGNETTING)
804 {
805 __OMP_PARALLEL_FOR_CPP__(firstprivate(modifier, tmpbuf, roi_out, pixelformat, ch))
806 for(int y = 0; y < roi_out->height; y++)
807 {
808 /* Colour correction: vignetting */
809 // actually this way row stride does not matter.
810 float *buf = tmpbuf + (size_t)y * ch * roi_out->width;
811 _lens_fill_vignette_row(buf, roi_out->width, ch);
812 modifier->ApplyColorModification(buf, roi_out->x, roi_out->y + y, roi_out->width, 1,
813 pixelformat, ch * roi_out->width);
814 }
815
816
817 /* _blocking_ memory transfer: host tmpbuf buffer -> opencl dev_tmpbuf */
818 err = dt_opencl_write_buffer_to_device(devid, tmpbuf, dev_tmpbuf, 0,
819 (size_t)ch * roi_out->width * roi_out->height * sizeof(float),
820 CL_TRUE);
821 if(err != CL_SUCCESS) goto error;
822
823 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 0, sizeof(cl_mem), (void *)&dev_tmp);
824 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 1, sizeof(cl_mem), (void *)&dev_out);
825 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 2, sizeof(int), (void *)&owidth);
826 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 3, sizeof(int), (void *)&oheight);
827 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 4, sizeof(cl_mem), (void *)&dev_tmpbuf);
828 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_lens_vignette, osizes);
829 if(err != CL_SUCCESS) goto error;
830 }
831 else
832 {
833 err = dt_opencl_enqueue_copy_image(devid, dev_tmp, dev_out, origin, origin, oregion);
834 if(err != CL_SUCCESS) goto error;
835 }
836 }
837
838 else // correct distortions:
839 {
840
841 if(modflags & LF_MODIFY_VIGNETTING)
842 {
843 __OMP_PARALLEL_FOR_CPP__(firstprivate(tmpbuf, ch, roi_in, pixelformat, modifier))
844 for(int y = 0; y < roi_in->height; y++)
845 {
846 /* Colour correction: vignetting */
847 // actually this way row stride does not matter.
848 float *buf = tmpbuf + (size_t)y * ch * roi_in->width;
849 _lens_fill_vignette_row(buf, roi_in->width, ch);
850 modifier->ApplyColorModification(buf, roi_in->x, roi_in->y + y, roi_in->width, 1,
851 pixelformat, ch * roi_in->width);
852 }
853
854
855 /* _blocking_ memory transfer: host tmpbuf buffer -> opencl dev_tmpbuf */
857 devid, tmpbuf, dev_tmpbuf, 0, (size_t)ch * roi_in->width * roi_in->height * sizeof(float), CL_TRUE);
858 if(err != CL_SUCCESS) goto error;
859
860 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 0, sizeof(cl_mem), (void *)&dev_in);
861 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 1, sizeof(cl_mem), (void *)&dev_tmp);
862 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 2, sizeof(int), (void *)&iwidth);
863 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 3, sizeof(int), (void *)&iheight);
864 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 4, sizeof(cl_mem), (void *)&dev_tmpbuf);
865 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_lens_vignette, isizes);
866 if(err != CL_SUCCESS) goto error;
867 }
868 else
869 {
870 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_tmp, origin, origin, iregion);
871 if(err != CL_SUCCESS) goto error;
872 }
873
874 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
875 {
876 __OMP_PARALLEL_FOR_CPP__(firstprivate(modifier, roi_out, tmpbuf, tmpbufwidth))
877 for(int y = 0; y < roi_out->height; y++)
878 {
879 float *pi = tmpbuf + (size_t)y * tmpbufwidth;
880 modifier->ApplySubpixelGeometryDistortion(roi_out->x, roi_out->y + y, roi_out->width, 1, pi);
881 }
882
883
884 /* _blocking_ memory transfer: host tmpbuf buffer -> opencl dev_tmpbuf */
885 err = dt_opencl_write_buffer_to_device(devid, tmpbuf, dev_tmpbuf, 0,
886 (size_t)owidth * oheight * 2 * 3 * sizeof(float), CL_TRUE);
887 if(err != CL_SUCCESS) goto error;
888
889 dt_opencl_set_kernel_arg(devid, ldkernel, 0, sizeof(cl_mem), (void *)&dev_tmp);
890 dt_opencl_set_kernel_arg(devid, ldkernel, 1, sizeof(cl_mem), (void *)&dev_out);
891 dt_opencl_set_kernel_arg(devid, ldkernel, 2, sizeof(int), (void *)&owidth);
892 dt_opencl_set_kernel_arg(devid, ldkernel, 3, sizeof(int), (void *)&oheight);
893 dt_opencl_set_kernel_arg(devid, ldkernel, 4, sizeof(int), (void *)&iwidth);
894 dt_opencl_set_kernel_arg(devid, ldkernel, 5, sizeof(int), (void *)&iheight);
895 dt_opencl_set_kernel_arg(devid, ldkernel, 6, sizeof(int), (void *)&roi_in_x);
896 dt_opencl_set_kernel_arg(devid, ldkernel, 7, sizeof(int), (void *)&roi_in_y);
897 dt_opencl_set_kernel_arg(devid, ldkernel, 8, sizeof(cl_mem), (void *)&dev_tmpbuf);
898 dt_opencl_set_kernel_arg(devid, ldkernel, 9, sizeof(int), (void *)&(d->do_nan_checks));
899 dt_opencl_set_kernel_arg(devid, ldkernel, 10, sizeof(int), (void *)&(raw_monochrome));
900 err = dt_opencl_enqueue_kernel_2d(devid, ldkernel, osizes);
901 if(err != CL_SUCCESS) goto error;
902 }
903 else
904 {
905 err = dt_opencl_enqueue_copy_image(devid, dev_tmp, dev_out, origin, origin, oregion);
906 if(err != CL_SUCCESS) goto error;
907 }
908 }
909
910 // See the matching comment in process(): don't gate the label on has_preview_output().
911 if(self->dev->gui_attached && !IS_NULL_PTR(g))
912 {
914 g->corrections_done = (modflags & LENSFUN_MODFLAG_MASK);
916 }
917
921 if(!IS_NULL_PTR(modifier)) delete modifier;
922 return TRUE;
923
924error:
928 if(!IS_NULL_PTR(modifier)) delete modifier;
929 dt_print(DT_DEBUG_OPENCL, "[opencl_lens] couldn't enqueue kernel! %d\n", err);
930 return FALSE;
931}
932#endif
933
934void 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)
935{
936 tiling->factor = 4.5f; // in + out + tmp + tmpbuf
937 tiling->maxbuf = 1.5f;
938 tiling->overhead = 0;
939 tiling->overlap = 4;
940 tiling->xalign = 1;
941 tiling->yalign = 1;
942 return;
943}
944
946 float *const __restrict points, size_t points_count)
947{
949 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f) return 0;
950
951 const float orig_w = piece->buf_in.width, orig_h = piece->buf_in.height;
952 int modflags;
953
954 const int used_lf_mask = (dt_image_is_monochrome(&self->dev->image_storage)) ? LF_MODIFY_ALL & ~LF_MODIFY_TCA : LF_MODIFY_ALL;
955
956 const lfModifier *modifier = get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, TRUE);
957 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
958 {
959 __OMP_PARALLEL_FOR_CPP__(firstprivate(points, points_count, modifier) if(points_count > 100))
960 for(size_t i = 0; i < points_count * 2; i += 2)
961 {
962 float DT_ALIGNED_ARRAY buf[6];
963 modifier->ApplySubpixelGeometryDistortion(points[i], points[i + 1], 1, 1, buf);
964 // take green channel distortion, like distort_mask() does, so x and y come from the
965 // same color channel's distortion field instead of mixing red's x with green's y.
966 points[i] = buf[2];
967 points[i + 1] = buf[3];
968 }
969 }
970
971 delete modifier;
972 return 1;
973}
974
976 float *const __restrict points, size_t points_count)
977{
979
980 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f) return 0;
981
982 const int used_lf_mask = (dt_image_is_monochrome(&self->dev->image_storage)) ? LF_MODIFY_ALL & ~LF_MODIFY_TCA : LF_MODIFY_ALL;
983
984 const float orig_w = piece->buf_in.width, orig_h = piece->buf_in.height;
985 int modflags;
986 const lfModifier *modifier = get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, FALSE);
987
988 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
989 {
990 __OMP_PARALLEL_FOR_CPP__(firstprivate(points_count, modifier, points) if(points_count > 100))
991 for(size_t i = 0; i < points_count * 2; i += 2)
992 {
993 float DT_ALIGNED_ARRAY buf[6];
994 modifier->ApplySubpixelGeometryDistortion(points[i], points[i + 1], 1, 1, buf);
995 // take green channel distortion, like distort_mask() does, so x and y come from the
996 // same color channel's distortion field instead of mixing red's x with green's y.
997 points[i] = buf[2];
998 points[i + 1] = buf[3];
999 }
1000 }
1001
1002 delete modifier;
1003 return 1;
1004}
1005
1006// TODO: Shall we keep LF_MODIFY_TCA in the modifiers?
1007void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece,
1008 const float *const in, float *const out, const dt_iop_roi_t *const roi_in,
1009 const dt_iop_roi_t *const roi_out)
1010{
1011 (void)pipe;
1012 const dt_iop_lensfun_data_t *const d = (dt_iop_lensfun_data_t *)piece->data;
1013
1014 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f)
1015 {
1016 dt_iop_image_copy_by_size(out, in, roi_out->width, roi_out->height, 1);
1017 return;
1018 }
1019
1020 const float orig_w = roi_in->scale * piece->buf_in.width, orig_h = roi_in->scale * piece->buf_in.height;
1022 int modflags;
1023 const lfModifier *modifier = get_modifier(&modflags, orig_w, orig_h, d, /*LF_MODIFY_TCA |*/ LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE, FALSE);
1024
1026
1027 if(!(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE)))
1028 {
1029 dt_iop_image_copy_by_size(out, in, roi_out->width, roi_out->height, 1);
1030 delete modifier;
1031 return;
1032 }
1033
1034 const struct dt_interpolation *const interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF_WARP);
1035
1036 // acquire temp memory for distorted pixel coords
1037 const size_t bufsize = (size_t)roi_out->width * 2 * 3;
1038 size_t padded_bufsize;
1039 float *const buf = dt_pixelpipe_cache_alloc_perthread_float(bufsize, &padded_bufsize);
1040 if(IS_NULL_PTR(buf)) return;
1041 __OMP_PARALLEL_FOR_CPP__(firstprivate(buf, padded_bufsize, d, modifier, in, out, interpolation, roi_in, roi_out))
1042 for(int y = 0; y < roi_out->height; y++)
1043 {
1044 float *bufptr = (float*)dt_get_perthread(buf, padded_bufsize);
1045 modifier->ApplySubpixelGeometryDistortion(roi_out->x, roi_out->y + y, roi_out->width, 1, bufptr);
1046
1047 // reverse transform the global coords from lf to our buffer
1048 float *_out = out + (size_t)y * roi_out->width;
1049 for(int x = 0; x < roi_out->width; x++, bufptr += 6, _out++)
1050 {
1051 if(d->do_nan_checks && (!isfinite(bufptr[2]) || !isfinite(bufptr[3])))
1052 {
1053 *_out = 0.0f;
1054 continue;
1055 }
1056
1057 // take green channel distortion also for alpha channel
1058 const float pi0 = bufptr[2] - roi_in->x;
1059 const float pi1 = bufptr[3] - roi_in->y;
1060 *_out = dt_interpolation_compute_sample(interpolation, in, pi0, pi1, roi_in->width, roi_in->height, 1,
1061 roi_in->width);
1062 }
1063 }
1064
1065
1067 delete modifier;
1068}
1069
1070void modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1071 struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out,
1072 const dt_iop_roi_t *roi_in)
1073{
1074 *roi_out = *roi_in;
1075}
1076
1077void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1078 struct dt_dev_pixelpipe_iop_t *piece,
1079 const dt_iop_roi_t *const roi_out, dt_iop_roi_t *roi_in)
1080{
1082 *roi_in = *roi_out;
1083 // inverse transform with given params
1084
1085 if(!d->lens || !d->lens->Maker || d->crop <= 0.0f) return;
1086
1087 const float orig_w = roi_in->scale * piece->buf_in.width;
1088 const float orig_h = roi_in->scale * piece->buf_in.height;
1089 int modflags;
1090 const lfModifier *modifier = get_modifier(&modflags, orig_w, orig_h, d, LF_MODIFY_ALL, FALSE);
1091
1092 if(modflags & (LF_MODIFY_TCA | LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE))
1093 {
1094 const int xoff = roi_in->x;
1095 const int yoff = roi_in->y;
1096 const int width = roi_in->width;
1097 const int height = roi_in->height;
1098 const int awidth = abs(width);
1099 const int aheight = abs(height);
1100 const int xstep = (width < 0) ? -1 : 1;
1101 const int ystep = (height < 0) ? -1 : 1;
1102
1103 float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX;
1104 const size_t nbpoints = 2 * awidth + 2 * aheight;
1105
1106 // ROI planning passes the active pipe now, but this temporary edge buffer only needs an
1107 // allocator bucket id, so use a stable generic bucket.
1108 float *const buf = (float *)dt_pixelpipe_cache_alloc_align_cache(sizeof(float) * nbpoints * 2 * 3,
1110 if(IS_NULL_PTR(buf)) return;
1111
1112#ifdef _OPENMP
1113#pragma omp parallel default(none) reduction(min : xm, ym) reduction(max : xM, yM) \
1114 firstprivate(modifier, xoff, yoff, awidth, aheight, width, height, nbpoints, ystep, xstep, buf)
1115#endif
1116 {
1117 __OMP_FOR__()
1118 for(int i = 0; i < awidth; i++)
1119 modifier->ApplySubpixelGeometryDistortion(xoff + i * xstep, yoff, 1, 1, buf + 6 * i);
1120 __OMP_FOR__()
1121 for(int i = 0; i < awidth; i++)
1122 modifier->ApplySubpixelGeometryDistortion(xoff + i * xstep, yoff + (height - 1), 1, 1, buf + 6 * (awidth + i));
1123 __OMP_FOR__()
1124 for(int j = 0; j < aheight; j++)
1125 modifier->ApplySubpixelGeometryDistortion(xoff, yoff + j * ystep, 1, 1, buf + 6 * (2 * awidth + j));
1126 __OMP_FOR__()
1127 for(int j = 0; j < aheight; j++)
1128 modifier->ApplySubpixelGeometryDistortion(xoff + (width - 1), yoff + j * ystep, 1, 1, buf + 6 * (2 * awidth + aheight + j));
1129
1130#ifdef _OPENMP
1131#pragma omp barrier
1132#endif
1133 __OMP_FOR__()
1134 for(size_t k = 0; k < nbpoints; k++)
1135 {
1136 // iterate over RGB channels x and y coordinates
1137 for(size_t c = 0; c < 6; c+=2)
1138 {
1139 const float x = buf[6 * k + c];
1140 const float y = buf[6 * k + c + 1];
1141 xm = isnan(x) ? xm : MIN(xm, x);
1142 xM = isnan(x) ? xM : MAX(xM, x);
1143 ym = isnan(y) ? ym : MIN(ym, y);
1144 yM = isnan(y) ? yM : MAX(yM, y);
1145 }
1146 }
1147 }
1148
1150
1151 // LensFun can return NAN coords, so we need to handle them carefully.
1152 if(!isfinite(xm) || !(0 <= xm && xm < orig_w)) xm = 0;
1153 if(!isfinite(xM) || !(1 <= xM && xM < orig_w)) xM = orig_w;
1154 if(!isfinite(ym) || !(0 <= ym && ym < orig_h)) ym = 0;
1155 if(!isfinite(yM) || !(1 <= yM && yM < orig_h)) yM = orig_h;
1156
1158 roi_in->x = fmaxf(0.0f, roundf(xm - interpolation->width));
1159 roi_in->y = fmaxf(0.0f, roundf(ym - interpolation->width));
1160 roi_in->width = roundf(fminf(orig_w - roi_in->x, xM - roi_in->x + interpolation->width));
1161 roi_in->height = roundf(fminf(orig_h - roi_in->y, yM - roi_in->y + interpolation->width));
1162
1163 // sanity check.
1164 roi_in->x = CLAMP(roi_in->x, 0, (int)floorf(orig_w));
1165 roi_in->y = CLAMP(roi_in->y, 0, (int)floorf(orig_h));
1166 roi_in->width = CLAMP(roi_in->width, 1, (int)ceilf(orig_w) - roi_in->x);
1167 roi_in->height = CLAMP(roi_in->height, 1, (int)ceilf(orig_h) - roi_in->y);
1168 }
1169 delete modifier;
1170}
1171
1174{
1176
1177 // FIXME: this is utter shit and should be made into a GUI "mode".
1178 // If p->modified == 0, mode = auto and hide all controls
1179 // if p->modidified == 1, mode = manual and show all controls.
1180 if(p->modified == 0)
1181 {
1182 /*
1183 * user did not modify anything in gui after autodetection - let's
1184 * use current default_params as params - for presets and mass-export
1185 */
1187
1188 // Temporary fix pending GUI unfucking
1189 dt_iop_compute_module_hash(self, self->dev->forms);
1190 }
1191
1193
1195 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
1196 const lfCamera *camera = NULL;
1197 const lfCamera **cam = NULL;
1198 if(d->lens)
1199 {
1200 delete d->lens;
1201 d->lens = NULL;
1202 }
1203 d->lens = new lfLens;
1204
1205 if(p->camera[0])
1206 {
1208 cam = dt_iop_lensfun_db->FindCamerasExt(NULL, p->camera, 0);
1209 if(cam)
1210 {
1211 camera = cam[0];
1212 d->crop = cam[0]->CropFactor;
1213 }
1215 }
1216 if(p->lens[0])
1217 {
1219 const lfLens **lens
1220 = dt_iop_lensfun_db->FindLenses(camera, NULL, p->lens, 0);
1222 if(lens)
1223 {
1224 *d->lens = *lens[0];
1225 if(p->tca_override)
1226 {
1227#ifdef LF_0395
1228 const dt_image_t *img = &(self->dev->image_storage);
1229
1230 d->custom_tca =
1231 {
1232 .Model = LF_TCA_MODEL_LINEAR,
1233 .Focal = p->focal,
1234 .Terms = { p->tca_r, p->tca_b },
1235 .CalibAttr = {
1236 .CenterX = 0.0f,
1237 .CenterY = 0.0f,
1238 .CropFactor = d->crop,
1239 .AspectRatio = (float)img->width / (float)img->height
1240 }
1241 };
1242#else
1243 // add manual d->lens stuff:
1244 lfLensCalibTCA tca = { LF_TCA_MODEL_NONE };
1245 tca.Focal = 0;
1246 tca.Model = LF_TCA_MODEL_LINEAR;
1247 tca.Terms[0] = p->tca_r;
1248 tca.Terms[1] = p->tca_b;
1249 if(d->lens->CalibTCA)
1250 while(d->lens->CalibTCA[0]) d->lens->RemoveCalibTCA(0);
1251 d->lens->AddCalibTCA(&tca);
1252#endif
1253 }
1254 lf_free(lens);
1255 }
1256 }
1257 lf_free(cam);
1258 d->modify_flags = p->modify_flags;
1259 if(dt_image_is_monochrome(&self->dev->image_storage)) d->modify_flags &= ~LF_MODIFY_TCA;
1260 d->inverse = p->inverse;
1261 d->scale = p->scale;
1262 d->focal = p->focal;
1263 d->aperture = p->aperture;
1264 d->distance = p->distance;
1265 d->target_geom = p->target_geom;
1266 d->do_nan_checks = TRUE;
1267 d->tca_override = p->tca_override;
1268
1269 /*
1270 * there are certain situations when LensFun can return NAN coordinated.
1271 * most common case would be when the FOV is increased.
1272 */
1273 if(d->target_geom == LF_RECTILINEAR)
1274 {
1275 d->do_nan_checks = FALSE;
1276 }
1277 else if(d->target_geom == d->lens->Type)
1278 {
1279 d->do_nan_checks = FALSE;
1280 }
1281
1282 piece->cache_output_on_ram = TRUE;
1283}
1284
1286{
1287 piece->data = dt_calloc_align(sizeof(dt_iop_lensfun_data_t));
1288 piece->data_size = sizeof(dt_iop_lensfun_data_t);
1289}
1290
1292{
1294
1295 if(d->lens)
1296 {
1297 delete d->lens;
1298 d->lens = NULL;
1299 }
1300 dt_free_align(piece->data);
1301 piece->data = NULL;
1302}
1303
1305{
1306 const int program = 2; // basic.cl, from programs.conf
1309 module->data = gd;
1310 gd->kernel_lens_distort_bilinear = dt_opencl_create_kernel(program, "lens_distort_bilinear");
1311 gd->kernel_lens_distort_bicubic = dt_opencl_create_kernel(program, "lens_distort_bicubic");
1312 gd->kernel_lens_distort_mitchell = dt_opencl_create_kernel(program, "lens_distort_mitchell");
1313 gd->kernel_lens_vignette = dt_opencl_create_kernel(program, "lens_vignette");
1314
1315 lfDatabase *dt_iop_lensfun_db = new lfDatabase;
1316 gd->db = (lfDatabase *)dt_iop_lensfun_db;
1317
1318#if defined(__MACH__) || defined(__APPLE__)
1319#else
1320 if(dt_iop_lensfun_db->Load() != LF_NO_ERROR)
1321#endif
1322 {
1323 char datadir[PATH_MAX] = { 0 };
1324 dt_loc_get_datadir(datadir, sizeof(datadir));
1325
1326 // get parent directory
1327 GFile *file = g_file_parse_name(datadir);
1328 GFile *parent = g_file_get_parent(file);
1329 gchar *path = g_file_get_path(parent);
1330 g_object_unref(parent);
1331 g_object_unref(file);
1332#ifdef LF_MAX_DATABASE_VERSION
1333 gchar *sysdbpath = g_build_filename(path, "lensfun", "version_" STR(LF_MAX_DATABASE_VERSION), (char *)NULL);
1334#endif
1335
1336#ifdef LF_0395
1337 const long userdbts = dt_iop_lensfun_db->ReadTimestamp(dt_iop_lensfun_db->UserUpdatesLocation);
1338 const long sysdbts = dt_iop_lensfun_db->ReadTimestamp(sysdbpath);
1339 const char *dbpath = userdbts > sysdbts ? dt_iop_lensfun_db->UserUpdatesLocation : sysdbpath;
1340 if(dt_iop_lensfun_db->Load(dbpath) != LF_NO_ERROR)
1341 fprintf(stderr, "[iop_lens]: could not load lensfun database in `%s'!\n", dbpath);
1342 else
1343 dt_iop_lensfun_db->Load(dt_iop_lensfun_db->UserLocation);
1344#else
1345 // code for older lensfun preserved as-is
1346#ifdef LF_MAX_DATABASE_VERSION
1347 dt_free(dt_iop_lensfun_db->HomeDataDir);
1348 dt_iop_lensfun_db->HomeDataDir = g_strdup(sysdbpath);
1349 if(dt_iop_lensfun_db->Load() != LF_NO_ERROR)
1350 {
1351 fprintf(stderr, "[iop_lens]: could not load lensfun database in `%s'!\n", sysdbpath);
1352#endif
1353 dt_free(dt_iop_lensfun_db->HomeDataDir);
1354 dt_iop_lensfun_db->HomeDataDir = g_build_filename(path, "lensfun", (char *)NULL);
1355 if(dt_iop_lensfun_db->Load() != LF_NO_ERROR)
1356 fprintf(stderr, "[iop_lens]: could not load lensfun database in `%s'!\n", dt_iop_lensfun_db->HomeDataDir);
1357#ifdef LF_MAX_DATABASE_VERSION
1358 }
1359#endif
1360#endif
1361
1362#ifdef LF_MAX_DATABASE_VERSION
1363 dt_free(sysdbpath);
1364#endif
1365 dt_free(path);
1366 }
1367}
1368
1369static float get_autoscale(dt_iop_module_t *self, dt_iop_lensfun_params_t *p, const lfCamera *camera);
1370
1372{
1373 char *new_lens;
1374 const dt_image_t *img = &module->dev->image_storage;
1375
1376 // reload image specific stuff
1377 // get all we can from exif:
1379
1380 new_lens = _lens_sanitize(img->exif_lens);
1381 g_strlcpy(d->lens, new_lens, sizeof(d->lens));
1382 dt_free(new_lens);
1383 g_strlcpy(d->camera, img->exif_model, sizeof(d->camera));
1384 d->crop = img->exif_crop;
1385 d->aperture = img->exif_aperture;
1386 d->focal = img->exif_focal_length;
1387 d->scale = 1.0;
1388 d->modify_flags = LF_MODIFY_TCA | LF_MODIFY_VIGNETTING | LF_MODIFY_DISTORTION |
1389 LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE;
1390 // if we did not find focus_distance in EXIF, lets default to 1000
1391 d->distance = img->exif_focus_distance == 0.0f ? 1000.0f : img->exif_focus_distance;
1392 d->target_geom = LF_RECTILINEAR;
1393
1394 if(dt_image_is_monochrome(img))
1395 d->modify_flags &= ~LF_MODIFY_TCA;
1396
1397 // init crop from db:
1398 char model[100]; // truncate often complex descriptions.
1399 g_strlcpy(model, img->exif_model, sizeof(model));
1400 for(char cnt = 0, *c = model; c < model + 100 && *c != '\0'; c++)
1401 if(*c == ' ')
1402 if(++cnt == 2) *c = '\0';
1403 if(img->exif_maker[0] || model[0])
1404 {
1406
1407 // just to be sure
1408 if(IS_NULL_PTR(gd) || IS_NULL_PTR(gd->db)) return;
1409
1411 const lfCamera **cam = gd->db->FindCamerasExt(img->exif_maker, img->exif_model, 0);
1413 if(cam)
1414 {
1416 const lfLens **lens = gd->db->FindLenses(cam[0], NULL, d->lens, 0);
1418
1419 if(!lens && islower(cam[0]->Mount[0]))
1420 {
1421 /*
1422 * This is a fixed-lens camera, and LF returned no lens.
1423 * (reasons: lens is "(65535)" or lens is correct lens name,
1424 * but LF have it as "fixed lens")
1425 *
1426 * Let's unset lens name and re-run lens query
1427 */
1428 g_strlcpy(d->lens, "", sizeof(d->lens));
1429
1431 lens = gd->db->FindLenses(cam[0], NULL, d->lens, 0);
1433 }
1434
1435 if(lens)
1436 {
1437 int lens_i = 0;
1438
1439 /*
1440 * Current SVN lensfun lets you test for a fixed-lens camera by looking
1441 * at the zeroth character in the mount's name:
1442 * If it is a lower case letter, it is a fixed-lens camera.
1443 */
1444 if(!d->lens[0] && islower(cam[0]->Mount[0]))
1445 {
1446 /*
1447 * no lens info in EXIF, and this is fixed-lens camera,
1448 * let's find shortest lens model in the list of possible lenses
1449 */
1450 size_t min_model_len = SIZE_MAX;
1451 for(int i = 0; lens[i]; i++)
1452 {
1453 if(strlen(lens[i]->Model) < min_model_len)
1454 {
1455 min_model_len = strlen(lens[i]->Model);
1456 lens_i = i;
1457 }
1458 }
1459
1460 // and set lens to it
1461 g_strlcpy(d->lens, lens[lens_i]->Model, sizeof(d->lens));
1462 }
1463
1464 d->target_geom = lens[lens_i]->Type;
1465 lf_free(lens);
1466 }
1467
1468 d->crop = cam[0]->CropFactor;
1469 d->scale = get_autoscale(module, d, cam[0]);
1470 module->workflow_enabled = dt_image_needs_rawprepare(img);
1471 lf_free(cam);
1472 }
1473 }
1474
1475 // The corrections-done message reset lives in gui_update() now (GUI thread, live widget);
1476 // reload_defaults() stays params-only and never touches gui_data.
1477}
1478
1480{
1482 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
1483 delete dt_iop_lensfun_db;
1484
1489 dt_free(module->data);
1490}
1491
1494
1495/* simple function to compute the floating-point precision
1496 which is enough for "normal use". The criteria is to have
1497 about 3 leading digits after the initial zeros. */
1498static int precision(double x, double adj)
1499{
1500 x *= adj;
1501
1502 if(x == 0) return 1;
1503 if(x < 1.0)
1504 if(x < 0.1)
1505 if(x < 0.01)
1506 return 5;
1507 else
1508 return 4;
1509 else
1510 return 3;
1511 else if(x < 100.0)
1512 if(x < 10.0)
1513 return 2;
1514 else
1515 return 1;
1516 else
1517 return 0;
1518}
1519
1520/* -- ufraw ptr array functions -- */
1521
1522static int ptr_array_insert_sorted(GPtrArray *array, const void *item, GCompareFunc compare)
1523{
1524 int length = array->len;
1525 g_ptr_array_set_size(array, length + 1);
1526 const void **root = (const void **)array->pdata;
1527
1528 int m = 0, l = 0, r = length - 1;
1529
1530 // Skip trailing NULL, if any
1531 if(l <= r && !root[r]) r--;
1532
1533 while(l <= r)
1534 {
1535 m = (l + r) / 2;
1536 int cmp = compare(root[m], item);
1537
1538 if(cmp == 0)
1539 {
1540 ++m;
1541 goto done;
1542 }
1543 else if(cmp < 0)
1544 l = m + 1;
1545 else
1546 r = m - 1;
1547 }
1548 if(r == m) m++;
1549
1550done:
1551 memmove(root + m + 1, root + m, sizeof(void *) * (length - m));
1552 root[m] = item;
1553 return m;
1554}
1555
1556static int ptr_array_find_sorted(const GPtrArray *array, const void *item, GCompareFunc compare)
1557{
1558 int length = array->len;
1559 void **root = array->pdata;
1560
1561 int l = 0, r = length - 1;
1562 int m = 0, cmp = 0;
1563
1564 if(!length) return -1;
1565
1566 // Skip trailing NULL, if any
1567 if(!root[r]) r--;
1568
1569 while(l <= r)
1570 {
1571 m = (l + r) / 2;
1572 cmp = compare(root[m], item);
1573
1574 if(cmp == 0)
1575 return m;
1576 else if(cmp < 0)
1577 l = m + 1;
1578 else
1579 r = m - 1;
1580 }
1581
1582 return -1;
1583}
1584
1585static void ptr_array_insert_index(GPtrArray *array, const void *item, int index)
1586{
1587 const void **root;
1588 int length = array->len;
1589 g_ptr_array_set_size(array, length + 1);
1590 root = (const void **)array->pdata;
1591 memmove(root + index + 1, root + index, sizeof(void *) * (length - index));
1592 root[index] = item;
1593}
1594
1595/* -- end ufraw ptr array functions -- */
1596
1597/* -- camera -- */
1598
1599static void camera_set(dt_iop_module_t *self, const lfCamera *cam)
1600{
1603 gchar *fm;
1604 const char *maker, *model, *variant;
1605 char _variant[100];
1606
1607 if(IS_NULL_PTR(cam))
1608 {
1609 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->camera_model))), "");
1610 gtk_widget_set_tooltip_text(GTK_WIDGET(g->camera_model), "");
1611 return;
1612 }
1613
1614 g_strlcpy(p->camera, cam->Model, sizeof(p->camera));
1615 p->crop = cam->CropFactor;
1616 g->camera = cam;
1617
1618 maker = lf_mlstr_get(cam->Maker);
1619 model = lf_mlstr_get(cam->Model);
1620 variant = lf_mlstr_get(cam->Variant);
1621
1622 if(model)
1623 {
1624 if(maker)
1625 fm = g_strdup_printf("%s, %s", maker, model);
1626 else
1627 fm = g_strdup_printf("%s", model);
1628 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->camera_model))), fm);
1629 dt_free(fm);
1630 }
1631
1632 if(variant)
1633 snprintf(_variant, sizeof(_variant), " (%s)", variant);
1634 else
1635 _variant[0] = 0;
1636
1637 fm = g_strdup_printf(_("maker:\t\t%s\n"
1638 "model:\t\t%s%s\n"
1639 "mount:\t\t%s\n"
1640 "crop factor:\t%.1f"),
1641 maker, model, _variant, cam->Mount, cam->CropFactor);
1642 gtk_widget_set_tooltip_text(GTK_WIDGET(g->camera_model), fm);
1643 dt_free(fm);
1644}
1645
1646static void camera_menu_select(GtkMenuItem *menuitem, gpointer user_data)
1647{
1648 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1649 camera_set(self, (lfCamera *)g_object_get_data(G_OBJECT(menuitem), "lfCamera"));
1650 if(dt_gui_widgets_suppressed()) return;
1652 p->modified = 1;
1654}
1655
1656static void camera_menu_fill(dt_iop_module_t *self, const lfCamera *const *camlist)
1657{
1659 unsigned i;
1660 GPtrArray *makers, *submenus;
1661
1662 if(g->camera_menu)
1663 {
1664 gtk_widget_destroy(GTK_WIDGET(g->camera_menu));
1665 g->camera_menu = NULL;
1666 }
1667
1668 /* Count all existing camera makers and create a sorted list */
1669 makers = g_ptr_array_new();
1670 submenus = g_ptr_array_new();
1671 for(i = 0; camlist[i]; i++)
1672 {
1673 GtkWidget *submenu, *item;
1674 const char *m = lf_mlstr_get(camlist[i]->Maker);
1675 int idx = ptr_array_find_sorted(makers, m, (GCompareFunc)g_utf8_collate);
1676 if(idx < 0)
1677 {
1678 /* No such maker yet, insert it into the array */
1679 idx = ptr_array_insert_sorted(makers, m, (GCompareFunc)g_utf8_collate);
1680 /* Create a submenu for cameras by this maker */
1681 submenu = gtk_menu_new();
1682 ptr_array_insert_index(submenus, submenu, idx);
1683 }
1684
1685 submenu = (GtkWidget *)g_ptr_array_index(submenus, idx);
1686 /* Append current camera name to the submenu */
1687 m = lf_mlstr_get(camlist[i]->Model);
1688 if(!camlist[i]->Variant)
1689 item = gtk_menu_item_new_with_label(m);
1690 else
1691 {
1692 gchar *fm = g_strdup_printf("%s (%s)", m, camlist[i]->Variant);
1693 item = gtk_menu_item_new_with_label(fm);
1694 dt_free(fm);
1695 }
1696 gtk_widget_show(item);
1697 g_object_set_data(G_OBJECT(item), "lfCamera", (void *)camlist[i]);
1698 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(camera_menu_select), self);
1699 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
1700 }
1701
1702 g->camera_menu = GTK_MENU(gtk_menu_new());
1703 for(i = 0; i < makers->len; i++)
1704 {
1705 GtkWidget *item = (GtkWidget *)gtk_menu_item_new_with_label((const gchar *)g_ptr_array_index(makers, i));
1706 gtk_widget_show(item);
1707 gtk_menu_shell_append(GTK_MENU_SHELL(g->camera_menu), item);
1708 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), (GtkWidget *)g_ptr_array_index(submenus, i));
1709 }
1710
1711 g_ptr_array_free(submenus, TRUE);
1712 g_ptr_array_free(makers, TRUE);
1713}
1714
1715static void parse_model(const char *txt, char *model, size_t sz_model)
1716{
1717 while(txt[0] && isspace(txt[0])) txt++;
1718 size_t len = strlen(txt);
1719 if(len > sz_model - 1) len = sz_model - 1;
1720 memcpy(model, txt, len);
1721 model[len] = 0;
1722}
1723
1724static void camera_menusearch_clicked(GtkWidget *button, gpointer user_data)
1725{
1726 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1728 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
1730
1731 (void)button;
1732
1733 const lfCamera *const *camlist;
1735 camlist = dt_iop_lensfun_db->GetCameras();
1737 if(IS_NULL_PTR(camlist)) return;
1738 camera_menu_fill(self, camlist);
1739
1740 dt_gui_menu_popup(GTK_MENU(g->camera_menu), button, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH);
1741}
1742
1743static void camera_autosearch_clicked(GtkWidget *button, gpointer user_data)
1744{
1745 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
1747 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
1749 char make[200], model[200];
1750 const gchar *txt = (const gchar *)((dt_iop_lensfun_params_t *)self->default_params)->camera;
1751
1752 (void)button;
1753
1754 if(txt[0] == '\0')
1755 {
1756 const lfCamera *const *camlist;
1758 camlist = dt_iop_lensfun_db->GetCameras();
1760 if(IS_NULL_PTR(camlist)) return;
1761 camera_menu_fill(self, camlist);
1762 }
1763 else
1764 {
1765 make[0] = '\0';
1766 parse_model(txt, model, sizeof(model));
1768 const lfCamera **camlist = dt_iop_lensfun_db->FindCamerasExt(make, model, 0);
1770 if(IS_NULL_PTR(camlist)) return;
1771 camera_menu_fill(self, camlist);
1772 lf_free(camlist);
1773 }
1774
1775 dt_gui_menu_popup(GTK_MENU(g->camera_menu), button, GDK_GRAVITY_SOUTH_EAST, GDK_GRAVITY_NORTH_EAST);
1776}
1777
1778/* -- end camera -- */
1779
1781{
1783 const char *text = dt_bauhaus_combobox_get_text(widget);
1784 if(text) (void)sscanf(text, "%f", &p->focal);
1785 p->modified = 1;
1787}
1788
1790{
1792 const char *text = dt_bauhaus_combobox_get_text(widget);
1793 if(text) (void)sscanf(text, "%f", &p->aperture);
1794 p->modified = 1;
1796}
1797
1799{
1801 const char *text = dt_bauhaus_combobox_get_text(widget);
1802 if(text) (void)sscanf(text, "%f", &p->distance);
1803 p->modified = 1;
1805}
1806
1807static void delete_children(GtkWidget *widget, gpointer data)
1808{
1809 (void)data;
1810 gtk_widget_destroy(widget);
1811}
1812
1813static void lens_set(dt_iop_module_t *self, const lfLens *lens)
1814{
1817
1818 gchar *fm;
1819 const char *maker, *model;
1820 unsigned i;
1821 gdouble focal_values[]
1822 = { -INFINITY, 4.5, 8, 10, 12, 14, 15, 16, 17, 18, 20, 24, 28, 30, 31, 35,
1823 38, 40, 43, 45, 50, 55, 60, 70, 75, 77, 80, 85, 90, 100, 105, 110,
1824 120, 135, 150, 200, 210, 240, 250, 300, 400, 500, 600, 800, 1000, INFINITY };
1825 gdouble aperture_values[]
1826 = { -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,
1827 5.6, 6.3, 7.1, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 29, 32, 38, INFINITY };
1828
1829 if(!lens)
1830 {
1831 gtk_widget_set_sensitive(GTK_WIDGET(g->modflags), FALSE);
1832 gtk_widget_set_sensitive(GTK_WIDGET(g->target_geom), FALSE);
1833 gtk_widget_set_sensitive(GTK_WIDGET(g->scale), FALSE);
1834 gtk_widget_set_sensitive(GTK_WIDGET(g->reverse), FALSE);
1835 gtk_widget_set_sensitive(GTK_WIDGET(g->tca_r), FALSE);
1836 gtk_widget_set_sensitive(GTK_WIDGET(g->tca_b), FALSE);
1837 gtk_widget_set_sensitive(GTK_WIDGET(g->message), FALSE);
1838
1839 g->trouble = TRUE;
1840 return;
1841 }
1842 else
1843 {
1844 // no longer in trouble
1845 gtk_widget_set_sensitive(GTK_WIDGET(g->modflags), TRUE);
1846 gtk_widget_set_sensitive(GTK_WIDGET(g->target_geom), TRUE);
1847 gtk_widget_set_sensitive(GTK_WIDGET(g->scale), TRUE);
1848 gtk_widget_set_sensitive(GTK_WIDGET(g->reverse), TRUE);
1849 gtk_widget_set_sensitive(GTK_WIDGET(g->tca_r), TRUE);
1850 gtk_widget_set_sensitive(GTK_WIDGET(g->tca_b), TRUE);
1851 gtk_widget_set_sensitive(GTK_WIDGET(g->message), TRUE);
1852
1853 g->trouble = FALSE;
1854 }
1855
1856 maker = lf_mlstr_get(lens->Maker);
1857 model = lf_mlstr_get(lens->Model);
1858
1859 g_strlcpy(p->lens, lens->Model, sizeof(p->lens));
1860
1861 if(model)
1862 {
1863 if(maker)
1864 fm = g_strdup_printf("%s, %s", maker, model);
1865 else
1866 fm = g_strdup_printf("%s", model);
1867 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->lens_model))), fm);
1868 dt_free(fm);
1869 }
1870
1871 char focal[100], aperture[100], mounts[200];
1872
1873 if(lens->MinFocal < lens->MaxFocal)
1874 snprintf(focal, sizeof(focal), "%g-%gmm", lens->MinFocal, lens->MaxFocal);
1875 else
1876 snprintf(focal, sizeof(focal), "%gmm", lens->MinFocal);
1877 if(lens->MinAperture < lens->MaxAperture)
1878 snprintf(aperture, sizeof(aperture), "%g-%g", lens->MinAperture, lens->MaxAperture);
1879 else
1880 snprintf(aperture, sizeof(aperture), "%g", lens->MinAperture);
1881
1882 mounts[0] = 0;
1883#ifdef LF_0395
1884 const char* const* mount_names = lens->GetMountNames();
1885 i = 0;
1886 while (mount_names && *mount_names) {
1887 if(i > 0) g_strlcat(mounts, ", ", sizeof(mounts));
1888 g_strlcat(mounts, *mount_names, sizeof(mounts));
1889 i++;
1890 mount_names++;
1891 }
1892#else
1893 if(lens->Mounts)
1894 for(i = 0; lens->Mounts[i]; i++)
1895 {
1896 if(i > 0) g_strlcat(mounts, ", ", sizeof(mounts));
1897 g_strlcat(mounts, lens->Mounts[i], sizeof(mounts));
1898 }
1899#endif
1900 fm = g_strdup_printf(_("maker:\t\t%s\n"
1901 "model:\t\t%s\n"
1902 "focal range:\t%s\n"
1903 "aperture:\t%s\n"
1904 "crop factor:\t%.1f\n"
1905 "type:\t\t%s\n"
1906 "mounts:\t%s"),
1907 maker ? maker : "?", model ? model : "?", focal, aperture,
1908#ifdef LF_0395
1909 g->camera->CropFactor,
1910#else
1911 lens->CropFactor,
1912#endif
1913 lfLens::GetLensTypeDesc(lens->Type, NULL), mounts);
1914
1915 gtk_widget_set_tooltip_text(GTK_WIDGET(g->lens_model), fm);
1916 dt_free(fm);
1917
1918 /* Create the focal/aperture/distance combo boxes */
1919 gtk_container_foreach(GTK_CONTAINER(g->lens_param_box), delete_children, NULL);
1920
1921 int ffi = 1, fli = -1;
1922 for(i = 1; i < sizeof(focal_values) / sizeof(gdouble) - 1; i++)
1923 {
1924 if(focal_values[i] < lens->MinFocal) ffi = i + 1;
1925 if(focal_values[i] > lens->MaxFocal && fli == -1) fli = i;
1926 }
1927 if(focal_values[ffi] > lens->MinFocal)
1928 {
1929 focal_values[ffi - 1] = lens->MinFocal;
1930 ffi--;
1931 }
1932 if(lens->MaxFocal == 0 || fli < 0) fli = sizeof(focal_values) / sizeof(gdouble) - 2;
1933 if(focal_values[fli + 1] < lens->MaxFocal)
1934 {
1935 focal_values[fli + 1] = lens->MaxFocal;
1936 ffi++;
1937 }
1938 if(fli < ffi) fli = ffi + 1;
1939
1940 GtkWidget *w;
1941 char txt[30];
1942
1943 // focal length
1945 dt_bauhaus_widget_set_label(w, N_("mm"));
1946 gtk_widget_set_tooltip_text(w, _("focal length (mm)"));
1947 snprintf(txt, sizeof(txt), "%.*f", precision(p->focal, 10.0), p->focal);
1949 for(int k = 0; k < fli - ffi; k++)
1950 {
1951 snprintf(txt, sizeof(txt), "%.*f", precision(focal_values[ffi + k], 10.0), focal_values[ffi + k]);
1953 }
1954 g_signal_connect(G_OBJECT(w), "value-changed", G_CALLBACK(lens_comboentry_focal_update), self);
1955 gtk_box_pack_start(GTK_BOX(g->lens_param_box), w, TRUE, TRUE, 0);
1957 g->cbe[0] = w;
1958
1959 // f-stop
1960 ffi = 1, fli = sizeof(aperture_values) / sizeof(gdouble) - 1;
1961 for(i = 1; i < sizeof(aperture_values) / sizeof(gdouble) - 1; i++)
1962 if(aperture_values[i] < lens->MinAperture) ffi = i + 1;
1963 if(aperture_values[ffi] > lens->MinAperture)
1964 {
1965 aperture_values[ffi - 1] = lens->MinAperture;
1966 ffi--;
1967 }
1968
1970 dt_bauhaus_widget_set_label(w, N_("f"));
1971 gtk_widget_set_tooltip_text(w, _("f-number (aperture)"));
1972 snprintf(txt, sizeof(txt), "%.*f", precision(p->aperture, 10.0), p->aperture);
1974 for(int k = 0; k < fli - ffi; k++)
1975 {
1976 snprintf(txt, sizeof(txt), "%.*f", precision(aperture_values[ffi + k], 10.0), aperture_values[ffi + k]);
1978 }
1979 g_signal_connect(G_OBJECT(w), "value-changed", G_CALLBACK(lens_comboentry_aperture_update), self);
1980 gtk_box_pack_start(GTK_BOX(g->lens_param_box), w, TRUE, TRUE, 0);
1982 g->cbe[1] = w;
1983
1985 dt_bauhaus_widget_set_label(w, N_("d"));
1986 gtk_widget_set_tooltip_text(w, _("distance to subject"));
1987 snprintf(txt, sizeof(txt), "%.*f", precision(p->distance, 10.0), p->distance);
1989 float val = 0.25f;
1990 for(int k = 0; k < 25; k++)
1991 {
1992 if(val > 1000.0f) val = 1000.0f;
1993 snprintf(txt, sizeof(txt), "%.*f", precision(val, 10.0), val);
1995 if(val >= 1000.0f) break;
1996 val *= sqrtf(2.0f);
1997 }
1998 g_signal_connect(G_OBJECT(w), "value-changed", G_CALLBACK(lens_comboentry_distance_update), self);
1999 gtk_box_pack_start(GTK_BOX(g->lens_param_box), w, TRUE, TRUE, 0);
2001 g->cbe[2] = w;
2002
2003 gtk_widget_show_all(g->lens_param_box);
2004}
2005
2006static void lens_menu_select(GtkMenuItem *menuitem, gpointer user_data)
2007{
2008 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2011 lens_set(self, (lfLens *)g_object_get_data(G_OBJECT(menuitem), "lfLens"));
2012 if(dt_gui_widgets_suppressed()) return;
2013 p->modified = 1;
2014 const float scale = get_autoscale(self, p, g->camera);
2015 dt_bauhaus_slider_set(g->scale, scale);
2017}
2018
2019static void lens_menu_fill(dt_iop_module_t *self, const lfLens *const *lenslist)
2020{
2022 unsigned i;
2023 GPtrArray *makers, *submenus;
2024
2025 if(g->lens_menu)
2026 {
2027 gtk_widget_destroy(GTK_WIDGET(g->lens_menu));
2028 g->lens_menu = NULL;
2029 }
2030
2031 /* Count all existing lens makers and create a sorted list */
2032 makers = g_ptr_array_new();
2033 submenus = g_ptr_array_new();
2034 for(i = 0; lenslist[i]; i++)
2035 {
2036 GtkWidget *submenu, *item;
2037 const char *m = lf_mlstr_get(lenslist[i]->Maker);
2038 int idx = ptr_array_find_sorted(makers, m, (GCompareFunc)g_utf8_collate);
2039 if(idx < 0)
2040 {
2041 /* No such maker yet, insert it into the array */
2042 idx = ptr_array_insert_sorted(makers, m, (GCompareFunc)g_utf8_collate);
2043 /* Create a submenu for lenses by this maker */
2044 submenu = gtk_menu_new();
2045 ptr_array_insert_index(submenus, submenu, idx);
2046 }
2047
2048 submenu = (GtkWidget *)g_ptr_array_index(submenus, idx);
2049 /* Append current lens name to the submenu */
2050 item = gtk_menu_item_new_with_label(lf_mlstr_get(lenslist[i]->Model));
2051 gtk_widget_show(item);
2052 g_object_set_data(G_OBJECT(item), "lfLens", (void *)lenslist[i]);
2053 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(lens_menu_select), self);
2054 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
2055 }
2056
2057 g->lens_menu = GTK_MENU(gtk_menu_new());
2058 for(i = 0; i < makers->len; i++)
2059 {
2060 GtkWidget *item = gtk_menu_item_new_with_label((const gchar *)g_ptr_array_index(makers, i));
2061 gtk_widget_show(item);
2062 gtk_menu_shell_append(GTK_MENU_SHELL(g->lens_menu), item);
2063 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), (GtkWidget *)g_ptr_array_index(submenus, i));
2064 }
2065
2066 g_ptr_array_free(submenus, TRUE);
2067 g_ptr_array_free(makers, TRUE);
2068}
2069
2070static void lens_menusearch_clicked(GtkWidget *button, gpointer user_data)
2071{
2072 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2074 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
2076 const lfLens **lenslist;
2077
2078 (void)button;
2079
2081 lenslist = dt_iop_lensfun_db->FindLenses(g->camera, NULL, NULL, LF_SEARCH_SORT_AND_UNIQUIFY);
2083 if(IS_NULL_PTR(lenslist)) return;
2084 lens_menu_fill(self, lenslist);
2085 lf_free(lenslist);
2086
2087 dt_gui_menu_popup(GTK_MENU(g->lens_menu), button, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH);
2088}
2089
2090static void lens_autosearch_clicked(GtkWidget *button, gpointer user_data)
2091{
2092 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2094 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
2096 const lfLens **lenslist;
2097 char model[200];
2098 const gchar *txt = ((dt_iop_lensfun_params_t *)self->default_params)->lens;
2099
2100 (void)button;
2101
2102 parse_model(txt, model, sizeof(model));
2104 lenslist = dt_iop_lensfun_db->FindLenses(g->camera, NULL,
2107 if(IS_NULL_PTR(lenslist)) return;
2108 lens_menu_fill(self, lenslist);
2109 lf_free(lenslist);
2110
2111 dt_gui_menu_popup(GTK_MENU(g->lens_menu), button, GDK_GRAVITY_SOUTH_EAST, GDK_GRAVITY_NORTH_EAST);
2112}
2113
2114/* -- end lens -- */
2115
2116static void target_geometry_changed(GtkWidget *widget, gpointer user_data)
2117{
2118 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2120
2121 int pos = dt_bauhaus_combobox_get(widget);
2122 p->target_geom = (lfLensType)(pos + LF_UNKNOWN + 1);
2123 p->modified = 1;
2125}
2126
2127static void modflags_changed(GtkWidget *widget, gpointer user_data)
2128{
2129 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2130 if(dt_gui_widgets_suppressed()) return;
2133 int pos = dt_bauhaus_combobox_get(widget);
2134 for(GList *modifiers = g->modifiers; modifiers; modifiers = g_list_next(modifiers))
2135 {
2137 if(mm->pos == pos)
2138 {
2139 p->modify_flags = (p->modify_flags & ~LENSFUN_MODFLAG_MASK) | mm->modflag;
2140 p->modified = 1;
2142 break;
2143 }
2144 }
2145}
2146
2147void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
2148{
2151 const gboolean raw_monochrome = dt_image_is_monochrome(&self->dev->image_storage);
2152 gtk_widget_set_visible(g->tca_override, !raw_monochrome);
2153 // update gui to show/hide tca sliders if tca_override was changed
2154 if(IS_NULL_PTR(w) || w == g->tca_override)
2155 {
2156 // show tca sliders only iff tca_overwrite is set
2157 gtk_widget_set_visible(g->tca_r, p->tca_override && !raw_monochrome);
2158 gtk_widget_set_visible(g->tca_b, p->tca_override && !raw_monochrome);
2159 }
2160
2161 if(w)
2162 {
2163 // user did modify something with some widget
2164 p->modified = 1;
2165 }
2166}
2167
2168
2169static float get_autoscale(dt_iop_module_t *self, dt_iop_lensfun_params_t *p, const lfCamera *camera)
2170{
2172 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
2173 float scale = 1.0;
2174 if(p->lens[0] != '\0')
2175 {
2177 const lfLens **lenslist
2178 = dt_iop_lensfun_db->FindLenses(camera, NULL, p->lens, 0);
2179 if(lenslist)
2180 {
2181 const dt_image_t *img = &(self->dev->image_storage);
2182
2183 // FIXME: get those from rawprepare IOP somehow !!!
2184 const int iwd = img->width - img->crop_x - img->crop_width,
2185 iht = img->height - img->crop_y - img->crop_height;
2186
2187 // create dummy modifier
2188#if defined(__GNUC__) && (__GNUC__ > 7)
2189 const dt_iop_lensfun_data_t d =
2190 {
2191 .lens = (lfLens *)lenslist[0],
2192 .modify_flags = p->modify_flags,
2193 .inverse = p->inverse,
2194 .scale = 1.0f,
2195 .crop = p->crop,
2196 .focal = p->focal,
2197 .aperture = p->aperture,
2198 .distance = p->distance,
2199 .target_geom = p->target_geom,
2200 .custom_tca = { .Model = LF_TCA_MODEL_NONE }
2201 };
2202#else
2203 // prior to GCC 8.x the / .custom_tca = { .Model = ??? } / was not supported:
2204 // sorry, unimplemented: non-trivial designated initializers not supported
2205 // ?? This code can be removed when GCC-7 is not used anymore.
2206
2208 d.lens = (lfLens *)lenslist[0];
2209 d.modify_flags = p->modify_flags;
2210 d.inverse = p->inverse;
2211 d.scale = 1.0f;
2212 d.crop = p->crop;
2213 d.focal = p->focal;
2214 d.aperture = p->aperture;
2215 d.distance = p->distance;
2216 d.target_geom = p->target_geom;
2217 d.custom_tca.Model = LF_TCA_MODEL_NONE;
2218#endif
2219
2220 lfModifier *modifier = get_modifier(NULL, iwd, iht, &d, LF_MODIFY_ALL, FALSE);
2221
2222 scale = modifier->GetAutoScale(p->inverse);
2223 delete modifier;
2224 }
2225 lf_free(lenslist);
2227 }
2228 return scale;
2229}
2230
2231static void autoscale_pressed(GtkWidget *button, gpointer user_data)
2232{
2233 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2236 const float scale = get_autoscale(self, p, g->camera);
2237 p->modified = 1;
2238 dt_bauhaus_slider_set(g->scale, scale);
2240}
2241
2242static void corrections_done(gpointer instance, gpointer user_data)
2243{
2244 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2246 if(dt_gui_widgets_suppressed()) return;
2247
2249 const int corrections_done = g->corrections_done;
2251
2252 const char empty_message[] = "";
2253 char *message = (char *)empty_message;
2254 for(GList *modifiers = g->modifiers; modifiers && self->enabled; modifiers = g_list_next(modifiers))
2255 {
2257 if(mm->modflag == corrections_done)
2258 {
2259 message = mm->name;
2260 break;
2261 }
2262 }
2263
2265 gtk_label_set_text(g->message, message);
2266 gtk_widget_set_tooltip_text(GTK_WIDGET(g->message), message);
2268}
2269
2270void gui_init(struct dt_iop_module_t *self)
2271{
2273
2274 g->camera = NULL;
2275 g->camera_menu = NULL;
2276 g->lens_menu = NULL;
2277 g->modifiers = NULL;
2278
2279 dt_iop_gui_enter_critical_section(self); // not actually needed, we're the only one with a ref to this instance
2280 g->corrections_done = -1;
2282
2283 // initialize modflags options
2284 int pos = -1;
2285 dt_iop_lensfun_modifier_t *modifier;
2286 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2287 dt_utf8_strlcpy(modifier->name, _("none"), sizeof(modifier->name));
2288 g->modifiers = g_list_append(g->modifiers, modifier);
2289 modifier->modflag = LENSFUN_MODFLAG_NONE;
2290 modifier->pos = ++pos;
2291
2292 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2293 dt_utf8_strlcpy(modifier->name, _("all"), sizeof(modifier->name));
2294 g->modifiers = g_list_append(g->modifiers, modifier);
2295 modifier->modflag = LENSFUN_MODFLAG_ALL;
2296 modifier->pos = ++pos;
2297
2298 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2299 dt_utf8_strlcpy(modifier->name, _("distortion & TCA"), sizeof(modifier->name));
2300 g->modifiers = g_list_append(g->modifiers, modifier);
2302 modifier->pos = ++pos;
2303
2304 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2305 dt_utf8_strlcpy(modifier->name, _("distortion & vignetting"), sizeof(modifier->name));
2306 g->modifiers = g_list_append(g->modifiers, modifier);
2308 modifier->pos = ++pos;
2309
2310 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2311 dt_utf8_strlcpy(modifier->name, _("TCA & vignetting"), sizeof(modifier->name));
2312 g->modifiers = g_list_append(g->modifiers, modifier);
2314 modifier->pos = ++pos;
2315
2316 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2317 dt_utf8_strlcpy(modifier->name, _("only distortion"), sizeof(modifier->name));
2318 g->modifiers = g_list_append(g->modifiers, modifier);
2319 modifier->modflag = LENSFUN_MODFLAG_DIST;
2320 modifier->pos = ++pos;
2321
2322 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2323 dt_utf8_strlcpy(modifier->name, _("only TCA"), sizeof(modifier->name));
2324 g->modifiers = g_list_append(g->modifiers, modifier);
2325 modifier->modflag = LENSFUN_MODFLAG_TCA;
2326 modifier->pos = ++pos;
2327
2328 modifier = (dt_iop_lensfun_modifier_t *)g_malloc0(sizeof(dt_iop_lensfun_modifier_t));
2329 dt_utf8_strlcpy(modifier->name, _("only vignetting"), sizeof(modifier->name));
2330 g->modifiers = g_list_append(g->modifiers, modifier);
2331 modifier->modflag = LENSFUN_MODFLAG_VIGN;
2332 modifier->pos = ++pos;
2333
2334 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
2335 gtk_widget_set_name(self->widget, "lens-module");
2336
2337 // camera selector
2338 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2339 g->camera_model = dt_iop_button_new(self, N_("camera model"),
2340 G_CALLBACK(camera_menusearch_clicked), FALSE, 0, (GdkModifierType)0,
2341 NULL, 0, hbox);
2342 g->find_camera_button = dt_iop_button_new(self, N_("find camera"),
2343 G_CALLBACK(camera_autosearch_clicked), FALSE, 0, (GdkModifierType)0,
2345 dt_gui_add_class(g->find_camera_button, "dt_big_btn_canvas");
2346 gtk_box_pack_start(GTK_BOX(hbox), g->find_camera_button, FALSE, FALSE, 0);
2347 gtk_box_pack_start(GTK_BOX(self->widget), hbox, TRUE, TRUE, 0);
2348
2349 // lens selector
2350 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2351 g->lens_model = dt_iop_button_new(self, N_("lens model"),
2352 G_CALLBACK(lens_menusearch_clicked), FALSE, 0, (GdkModifierType)0,
2353 NULL, 0, hbox);
2354 g->find_lens_button = dt_iop_button_new(self, N_("find lens"),
2355 G_CALLBACK(lens_autosearch_clicked), FALSE, 0, (GdkModifierType)0,
2357 dt_gui_add_class(g->find_lens_button, "dt_big_btn_canvas");
2358 gtk_box_pack_start(GTK_BOX(hbox), g->find_lens_button, FALSE, FALSE, 0);
2359 gtk_box_pack_start(GTK_BOX(self->widget), hbox, TRUE, TRUE, 0);
2360
2361 // lens properties
2362 g->lens_param_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2363 gtk_box_pack_start(GTK_BOX(self->widget), g->lens_param_box, TRUE, TRUE, 0);
2364
2365#if 0
2366 // if unambiguous info is there, use it.
2367 if(self->dev->image_storage.exif_lens[0] != '\0')
2368 {
2369 char make [200], model [200];
2370 const gchar *txt = gtk_entry_get_text(GTK_ENTRY(g->lens_model));
2371 parse_maker_model (txt, make, sizeof (make), model, sizeof (model));
2373 const lfLens **lenslist = lf_db_find_lenses_hd (dt_iop_lensfun_db, g->camera,
2374 make [0] ? make : NULL,
2375 model [0] ? model : NULL, 0);
2376 if(lenslist) lens_set (self, lenslist[0]);
2377 lf_free (lenslist);
2379 }
2380#endif
2381
2382 // selector for correction type (modflags): one or more out of distortion, TCA, vignetting
2384 dt_bauhaus_widget_set_label(g->modflags, N_("corrections"));
2385 gtk_box_pack_start(GTK_BOX(self->widget), g->modflags, TRUE, TRUE, 0);
2386 gtk_widget_set_tooltip_text(g->modflags, _("which corrections to apply"));
2387 GList *l = g->modifiers;
2388 while(l)
2389 {
2390 modifier = (dt_iop_lensfun_modifier_t *)l->data;
2391 dt_bauhaus_combobox_add(g->modflags, modifier->name);
2392 l = g_list_next(l);
2393 }
2394 dt_bauhaus_combobox_set(g->modflags, 0);
2395 g_signal_connect(G_OBJECT(g->modflags), "value-changed", G_CALLBACK(modflags_changed), (gpointer)self);
2396
2397 // target geometry
2399 dt_bauhaus_widget_set_label(g->target_geom, N_("geometry"));
2400 gtk_box_pack_start(GTK_BOX(self->widget), g->target_geom, TRUE, TRUE, 0);
2401 gtk_widget_set_tooltip_text(g->target_geom, _("target geometry"));
2402 dt_bauhaus_combobox_add(g->target_geom, _("rectilinear"));
2403 dt_bauhaus_combobox_add(g->target_geom, _("fish-eye"));
2404 dt_bauhaus_combobox_add(g->target_geom, _("panoramic"));
2405 dt_bauhaus_combobox_add(g->target_geom, _("equirectangular"));
2406#if LF_VERSION >= ((0 << 24) | (2 << 16) | (6 << 8) | 0)
2407 dt_bauhaus_combobox_add(g->target_geom, _("orthographic"));
2408 dt_bauhaus_combobox_add(g->target_geom, _("stereographic"));
2409 dt_bauhaus_combobox_add(g->target_geom, _("equisolid angle"));
2410 dt_bauhaus_combobox_add(g->target_geom, _("thoby fish-eye"));
2411#endif
2412 g_signal_connect(G_OBJECT(g->target_geom), "value-changed", G_CALLBACK(target_geometry_changed),
2413 (gpointer)self);
2414
2415 // scale
2416 g->scale = dt_bauhaus_slider_from_params(self, N_("scale"));
2419 g_signal_connect(G_OBJECT(g->scale), "quad-pressed", G_CALLBACK(autoscale_pressed), self);
2420 gtk_widget_set_tooltip_text(g->scale, _("auto scale"));
2421
2422 // reverse direction
2423 g->reverse = dt_bauhaus_combobox_from_params(self, "inverse");
2424 dt_bauhaus_combobox_add(g->reverse, _("correct"));
2425 dt_bauhaus_combobox_add(g->reverse, _("distort"));
2426 gtk_widget_set_tooltip_text(g->reverse, _("correct distortions or apply them"));
2427
2428 g->tca_override = dt_bauhaus_toggle_from_params(self, "tca_override");
2429
2430 // override linear tca (if not 1.0):
2431 g->tca_r = dt_bauhaus_slider_from_params(self, "tca_r");
2433 gtk_widget_set_tooltip_text(g->tca_r, _("Transversal Chromatic Aberration red"));
2434
2435 g->tca_b = dt_bauhaus_slider_from_params(self, "tca_b");
2437 gtk_widget_set_tooltip_text(g->tca_b, _("Transversal Chromatic Aberration blue"));
2438
2439 // message box to inform user what corrections have been done. this is useful as depending on lensfuns
2440 // profile only some of the lens flaws can be corrected
2441 GtkBox *hbox1 = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
2442 GtkWidget *label = gtk_label_new(_("corrections done: "));
2443 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE);
2444 gtk_widget_set_tooltip_text(label, _("which corrections have actually been done"));
2445 gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
2446 g->message = GTK_LABEL(gtk_label_new("")); // This gets filled in by process
2447 gtk_label_set_ellipsize(GTK_LABEL(g->message), PANGO_ELLIPSIZE_MIDDLE);
2448 gtk_box_pack_start(GTK_BOX(hbox1), GTK_WIDGET(g->message), FALSE, FALSE, 0);
2449 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox1), TRUE, TRUE, 0);
2450
2451 /* add signal handler for preview pipe finish to update message on corrections done */
2453 G_CALLBACK(corrections_done), self);
2454}
2455
2456void gui_update(struct dt_iop_module_t *self)
2457{
2458 // let gui elements reflect params
2461
2462 if(p->modified == 0)
2463 {
2464 /*
2465 * user did not modify anything in gui after autodetection - let's
2466 * use current default_params as params - for presets and mass-export
2467 */
2468 memcpy(self->params, self->default_params, sizeof(dt_iop_lensfun_params_t));
2469 }
2470
2472 lfDatabase *dt_iop_lensfun_db = (lfDatabase *)gd->db;
2473 // these are the wrong (untranslated) strings in general but that's ok, they will be overwritten further
2474 // down
2475 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->camera_model))), p->camera);
2476 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->lens_model))), p->lens);
2477 gtk_widget_set_tooltip_text(g->camera_model, "");
2478 gtk_widget_set_tooltip_text(g->lens_model, "");
2479
2480 int modflag = p->modify_flags & LENSFUN_MODFLAG_MASK;
2481 for(GList *modifiers = g->modifiers; modifiers; modifiers = g_list_next(modifiers))
2482 {
2484 if(mm->modflag == modflag)
2485 {
2486 dt_bauhaus_combobox_set(g->modflags, mm->pos);
2487 break;
2488 }
2489 }
2490
2491 dt_bauhaus_combobox_set(g->target_geom, p->target_geom - LF_UNKNOWN - 1);
2492 dt_bauhaus_combobox_set(g->reverse, p->inverse);
2493 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->tca_override), p->tca_override);
2494 const lfCamera **cam = NULL;
2495 g->camera = NULL;
2496 if(p->camera[0])
2497 {
2499 cam = dt_iop_lensfun_db->FindCamerasExt(NULL, p->camera, 0);
2501 if(cam)
2502 camera_set(self, cam[0]);
2503 else
2504 camera_set(self, NULL);
2505 lf_free(cam);
2506 }
2507 if(g->camera && p->lens[0])
2508 {
2509 char model[200];
2510 parse_model(p->lens, model, sizeof(model));
2512 const lfLens **lenslist = dt_iop_lensfun_db->FindLenses(g->camera, NULL,
2513 model[0] ? model : NULL, 0);
2514 if(lenslist)
2515 lens_set(self, lenslist[0]);
2516 else
2517 lens_set(self, NULL);
2518 lf_free(lenslist);
2520 }
2521 else
2522 {
2524 lens_set(self, NULL);
2526 }
2527
2528 // Default to blank: safe fallback if the piece isn't ready yet (e.g. very first call for this
2529 // image, before any pipe sync happened).
2531 g->corrections_done = -1;
2533 gtk_label_set_text(g->message, "");
2534
2535 // Which corrections are actually available/applied only depends on the current camera+lens+params
2536 // combo, not on process() having just run -- so don't gate the label on the pixel pipe having
2537 // (re)executed (it may not: a pixelpipe cache hit skips process() entirely, e.g. after undo/redo
2538 // to a recently-rendered history state, leaving the label blank forever otherwise). commit_params()
2539 // already wrote this exact lensfun data into the synced piece regardless of that; read it back the
2540 // same GUI-thread-safe way ashift reads piece->buf_in from the virtual pipe.
2541 const dt_dev_pixelpipe_iop_t *lens_piece = dt_dev_distort_get_iop_pipe(self->dev->virtual_pipe, self);
2542 const dt_iop_lensfun_data_t *lens_d
2543 = (!IS_NULL_PTR(lens_piece)) ? (const dt_iop_lensfun_data_t *)lens_piece->data : NULL;
2544 if(!IS_NULL_PTR(lens_d) && !IS_NULL_PTR(lens_d->lens) && !IS_NULL_PTR(lens_d->lens->Maker) && lens_d->crop > 0.0f
2545 && lens_piece->buf_in.width > 0 && lens_piece->buf_in.height > 0)
2546 {
2547 const gboolean raw_monochrome = dt_image_is_monochrome(&self->dev->image_storage);
2548 const int used_lf_mask = raw_monochrome ? (LF_MODIFY_ALL & ~LF_MODIFY_TCA) : LF_MODIFY_ALL;
2549 int modflags = 0;
2550 lfModifier *modifier = get_modifier(&modflags, lens_piece->buf_in.width, lens_piece->buf_in.height,
2551 lens_d, used_lf_mask, FALSE);
2552 delete modifier;
2553
2555 g->corrections_done = modflags & LENSFUN_MODFLAG_MASK;
2557
2558 for(GList *modifiers = g->modifiers; !IS_NULL_PTR(modifiers); modifiers = g_list_next(modifiers))
2559 {
2561 if(mm->modflag == g->corrections_done)
2562 {
2563 gtk_label_set_text(g->message, mm->name);
2564 gtk_widget_set_tooltip_text(GTK_WIDGET(g->message), mm->name);
2565 break;
2566 }
2567 }
2568 }
2569
2570 gui_changed(self, NULL, NULL);
2571}
2572
2574{
2576
2578
2579 while(g->modifiers)
2580 {
2581 dt_free(g->modifiers->data);
2582 g->modifiers = g_list_delete_link(g->modifiers, g->modifiers);
2583 }
2584
2586}
2587
2588}
2589
2590// clang-format off
2591// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2592// vim: shiftwidth=2 expandtab tabstop=2 cindent
2593// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2594// 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:3549
void dt_bauhaus_combobox_set_editable(GtkWidget *widget, int editable)
Definition bauhaus.c:2077
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2350
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
Definition bauhaus.c:2165
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3537
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2304
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1656
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1845
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2019
void dt_bauhaus_widget_set_quad_paint(GtkWidget *widget, dt_bauhaus_quad_paint_f f, int paint_flags, void *paint_data)
Definition bauhaus.c:1705
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:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
#define STR(x)
Definition darktable.h:182
#define dt_free_align(ptr)
Definition darktable.h:503
static void * dt_calloc_align(size_t size)
Definition darktable.h:510
@ DT_DEBUG_OPENCL
Definition darktable.h:744
#define DT_ALIGNED_ARRAY
Definition darktable.h:400
#define dt_gui_freeze_begin()
Definition darktable.h:900
#define dt_gui_freeze_end()
Definition darktable.h:901
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:445
#define __OMP_FOR__(...)
Definition darktable.h:273
#define dt_free(ptr)
Definition darktable.h:478
void void void gboolean dt_gui_widgets_suppressed(void)
Definition gtk.c:194
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
Definition darktable.h:151
#define __OMP_PARALLEL_FOR_CPP__(...)
Definition darktable.h:277
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:475
#define __DT_CLONE_TARGETS__
Definition darktable.h:379
#define dt_get_perthread(buf, padsize)
Definition darktable.h:1097
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
Definition darktable.h:1092
#define DT_PIXEL_SIMD_CHANNELS
Definition darktable.h:660
#define PATH_MAX
Definition darktable.h:1189
#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:293
#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:42
dt_dev_pixelpipe_iop_t * dt_dev_distort_get_iop_pipe(struct dt_dev_pixelpipe_t *pipe, struct dt_iop_module_t *module)
Definition develop.c:1657
@ 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:384
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
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:3185
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:1928
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:3220
#define IOP_GUI_FREE
Definition imageop.h:641
static void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module) ACQUIRE(&module -> gui_lock)
Definition imageop.h:450
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:199
@ IOP_FLAGS_UNSAFE_COPY
Definition imageop.h:207
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:201
static void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module) RELEASE(&module -> gui_lock)
Definition imageop.h:456
@ IOP_GROUP_REPAIR
Definition imageop.h:170
#define IOP_GUI_ALLOC(module)
Definition imageop.h:638
@ IOP_TAG_DISTORT
Definition imageop.h:181
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:975
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:1172
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:1007
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:1556
static void lens_set(dt_iop_module_t *self, const lfLens *lens)
Definition lens.cc:1813
void reload_defaults(dt_iop_module_t *module)
Definition lens.cc:1371
static void lens_comboentry_distance_update(GtkWidget *widget, dt_iop_module_t *self)
Definition lens.cc:1798
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:2090
static void autoscale_pressed(GtkWidget *button, gpointer user_data)
Definition lens.cc:2231
__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:1646
static void camera_set(dt_iop_module_t *self, const lfCamera *cam)
Definition lens.cc:1599
const char * aliases()
Definition lens.cc:199
static void lens_comboentry_focal_update(GtkWidget *widget, dt_iop_module_t *self)
Definition lens.cc:1780
static void camera_menusearch_clicked(GtkWidget *button, gpointer user_data)
Definition lens.cc:1724
static void lens_comboentry_aperture_update(GtkWidget *widget, dt_iop_module_t *self)
Definition lens.cc:1789
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:1285
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:945
static void ptr_array_insert_index(GPtrArray *array, const void *item, int index)
Definition lens.cc:1585
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
Definition lens.cc:2456
static int precision(double x, double adj)
Definition lens.cc:1498
void gui_init(struct dt_iop_module_t *self)
Definition lens.cc:2270
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition lens.cc:2147
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:934
static float get_autoscale(dt_iop_module_t *self, dt_iop_lensfun_params_t *p, const lfCamera *camera)
Definition lens.cc:2169
static void lens_menu_fill(dt_iop_module_t *self, const lfLens *const *lenslist)
Definition lens.cc:2019
void cleanup_global(dt_iop_module_so_t *module)
Definition lens.cc:1479
static void camera_menu_fill(dt_iop_module_t *self, const lfCamera *const *camlist)
Definition lens.cc:1656
static void corrections_done(gpointer instance, gpointer user_data)
Definition lens.cc:2242
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:2070
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:1077
void gui_cleanup(struct dt_iop_module_t *self)
Definition lens.cc:2573
static int ptr_array_insert_sorted(GPtrArray *array, const void *item, GCompareFunc compare)
Definition lens.cc:1522
static void lens_menu_select(GtkMenuItem *menuitem, gpointer user_data)
Definition lens.cc:2006
static void target_geometry_changed(GtkWidget *widget, gpointer user_data)
Definition lens.cc:2116
static void parse_model(const char *txt, char *model, size_t sz_model)
Definition lens.cc:1715
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition lens.cc:1291
static void delete_children(GtkWidget *widget, gpointer data)
Definition lens.cc:1807
void init_global(dt_iop_module_so_t *module)
Definition lens.cc:1304
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:682
static void modflags_changed(GtkWidget *widget, gpointer user_data)
Definition lens.cc:2127
static void camera_autosearch_clicked(GtkWidget *button, gpointer user_data)
Definition lens.cc:1743
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:1070
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:2164
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
Definition opencl.c:2580
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2504
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2058
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:2348
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
Definition opencl.c:2289
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2101
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
Definition opencl.c:2155
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2415
#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:387
@ 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:376
struct _GtkWidget GtkWidget
Definition splash.h:29
const float r
dt_pthread_mutex_t plugin_threadsafe
Definition darktable.h:821
struct dt_control_signal_t * signals
Definition darktable.h:802
struct dt_bauhaus_t * bauhaus
Definition darktable.h:806
struct dt_develop_t * develop
Definition darktable.h:798
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
struct dt_dev_pixelpipe_t * virtual_pipe
Definition develop.h:251
GList * forms
Definition develop.h:327
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:263
dt_iop_params_t * default_params
Definition imageop.h:344
GtkWidget * widget
Definition imageop.h:374
struct dt_develop_t * dev
Definition imageop.h:333
dt_iop_gui_data_t * gui_data
Definition imageop.h:348
dt_iop_global_data_t * global_data
Definition imageop.h:351
gboolean enabled
Definition imageop.h:335
dt_iop_params_t * params
Definition imageop.h:344
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
size_t dt_utf8_strlcpy(char *dest, const char *src, size_t n)
Definition utility.c:289