Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
lens.c
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 Copyright (C) 2026 Guillaume Stutin.
55
56 darktable is free software: you can redistribute it and/or modify
57 it under the terms of the GNU General Public License as published by
58 the Free Software Foundation, either version 3 of the License, or
59 (at your option) any later version.
60
61 darktable is distributed in the hope that it will be useful,
62 but WITHOUT ANY WARRANTY; without even the implied warranty of
63 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
64 GNU General Public License for more details.
65
66 You should have received a copy of the GNU General Public License
67 along with darktable. If not, see <http://www.gnu.org/licenses/>.
68*/
70#include "common/paths.h" // DT_PATH_MAX
71#include "common/utility.h"
72#include "system/macros.h"
74#include "common/logging.h"
75#include "system/mem_alloc.h"
76#include "system/openmp.h"
79#include "glib.h"
80
81#ifdef HAVE_CONFIG_H
82#include "config.h"
83#endif
84#include "widgets/bauhaus.h"
85#include "pixel/interpolation.h"
87#include "common/imagebuf.h"
88#include "common/opencl.h"
89#include "develop/develop.h"
90#include "develop/imageop.h"
91#include "develop/imageop_gui.h"
92#include "develop/tiling.h"
93
94#include "iop/iop_api.h"
95#include <assert.h>
96#include <ctype.h>
97#include <gtk/gtk.h>
98#include <inttypes.h>
99#include <math.h>
100#include <stdlib.h>
101#include <string.h>
102
103#include "widgets/popup.h"
104#include "widgets/widget_style.h"
105#include "control/signal.h"
106
108
109#include "lensserious.h" // side-by-side latch against lensfun, see feat/lensserious
110#include "lensserious_db.h" // ... and its calibration database, latched the same way
111#include "lensserious_vendor.h"
112
113
114/* The correction axes and the projection numbering.
115 *
116 * These values are lensfun's, and they must stay lensfun's: `modify_flags` and
117 * `target_geom` are SERIALIZED into every user's history and every preset that has ever
118 * been saved. Defining them here rather than including them is what lets liblensfun go
119 * without rewriting anyone's edits.
120 *
121 * The projection numbering is also, entry for entry, ls_lens_type_t's -- asserted below
122 * rather than assumed, because the two now live in different repositories and nothing else
123 * would notice one of them growing a member in the middle. */
167{
168 /* --- low half: lensfun's serialized axis numbering, unchangeable --- */
169 DT_LENS_MODIFY_TCA = 0x00000001,
174
175 /* --- high half: how far up sits each axis's two-bit source field --- */
181
192#define DT_LENS_MODIFY_DISTORTION_PACK \
193 (DT_LENS_MODIFY_DISTORTION | DT_LENS_MODIFY_GEOMETRY | DT_LENS_MODIFY_SCALE)
194
196#define DT_LENS_MODIFY_ANSEL_MASK 0xFF000000u
197
206#define DT_LENS_MODIFY_ALL_AXES ((int)~DT_LENS_MODIFY_ANSEL_MASK)
207
208/* The boundary, checked rather than described. Each of these is a way the two halves could
209 * come to overlap -- a sixth axis assigned too high, a source field assigned too low, a
210 * field running into the sign bit -- and each would corrupt the other half's meaning in a
211 * way that only shows up as a wrong correction on someone's photograph. */
212_Static_assert((DT_LENS_MODIFY_ALL_AXES & (int)DT_LENS_MODIFY_ANSEL_MASK) == 0,
213 "the axis space and Ansel's own bits must not overlap");
217 "every correction axis must live in the axis half");
219 "no source field may reach the sign bit of modify_flags");
222 "the source fields must not overlap each other");
223
232
258
271
272_Static_assert((int)DT_LENS_RECTILINEAR == (int)LS_LENS_RECTILINEAR
273 && (int)DT_LENS_FISHEYE == (int)LS_LENS_FISHEYE
280 "projection numbering must match ls_lens_type_t: stored params depend on it");
281
283
285{
286 /* The three axes a user can actually see corrected. Geometry and scale are not in it:
287 * they are how the correction is presented, not whether a lens flaw was fixed. */
290
291
293{
295 int inverse; // $MIN: 0 $MAX: 1 $DEFAULT: 0 $DESCRIPTION: "mode"
296 float scale; // $MIN: 0.1 $MAX: 2.0 $DEFAULT: 1.0
297 float crop;
298 float focal;
299 float aperture;
300 float distance;
301 dt_lens_type_t target_geom; // $DEFAULT: DT_LENS_RECTILINEAR $DESCRIPTION: "geometry"
302 char camera[128];
303 char lens[128];
304 gboolean tca_override; // $DEFAULT: FALSE $DESCRIPTION: "TCA overwrite"
305 float tca_r; // $MIN: 0.99 $MAX: 1.01 $DEFAULT: 1.0 $DESCRIPTION: "TCA red"
306 float tca_b; // $MIN: 0.99 $MAX: 1.01 $DEFAULT: 1.0 $DESCRIPTION: "TCA blue"
311 int modified; // $DEFAULT: 1
313
314/* ========================================================================================
315 * The modify_flags interface.
316 *
317 * Everything below this banner and above the next one is the only code in this file allowed
318 * to touch a bit of modify_flags. Everything else asks in terms of an axis and a source.
319 *
320 * That rule is not tidiness. The encoding has three traps, and each has already been walked
321 * into once: the source fields are two bits at a shift that is not the axis's bit position;
322 * the distortion "bit" is really three bits, so clearing the obvious one leaves projection
323 * and scaling running with their controls hidden; and manual TCA is ALSO recorded in a
324 * separate legacy boolean, so writing one without the other makes an edit mean two different
325 * things depending on which the reader trusts.
326 * ===================================================================================== */
327
331static inline int _lens_axis_flags(const dt_lens_axis_t axis)
332{
333 switch(axis)
334 {
338 default: return 0;
339 }
340}
341
353
355static inline int _lens_axis_shift(const dt_lens_axis_t axis)
356{
357 switch(axis)
358 {
362 default: return DT_LENS_SOURCE_SHIFT_TCA;
363 }
364}
365
374static inline gboolean _lens_source_applicable(const dt_lens_axis_t axis,
375 const dt_lens_source_t source)
376{
377 if(source == DT_LENS_SOURCE_MANUAL) return axis == DT_LENS_AXIS_TCA;
378 return source > DT_LENS_SOURCE_OFF && source < DT_LENS_SOURCE_LAST;
379}
380
392static dt_lens_source_t _lens_source_decode(const int modify_flags,
393 const gboolean tca_override,
394 const dt_lens_axis_t axis)
395{
396 if(!(modify_flags & _lens_axis_presence_bit(axis))) return DT_LENS_SOURCE_OFF;
397
398 dt_lens_source_t source
400
401 /* Zero is the database, because that is what every edit written before this decoded to. */
402 if(source == DT_LENS_SOURCE_OFF) source = DT_LENS_SOURCE_LENSFUN;
403
404 if(axis == DT_LENS_AXIS_TCA && source == DT_LENS_SOURCE_LENSFUN && tca_override)
405 source = DT_LENS_SOURCE_MANUAL;
406
407 /* A value this build has no meaning for -- a newer Ansel wrote it, or the field was
408 * corrupted. Correcting with the database beats refusing to correct at all. */
410
411 return source;
412}
413
416 const dt_lens_axis_t axis)
417{
418 return _lens_source_decode(p->modify_flags, p->tca_override, axis);
419}
420
433 dt_lens_source_t source)
434{
435 if(!_lens_source_applicable(axis, source)) source = DT_LENS_SOURCE_OFF;
436
437 p->modify_flags &= ~(DT_LENS_SOURCE_BITS << _lens_axis_shift(axis));
438
439 if(source == DT_LENS_SOURCE_OFF)
440 {
441 /* The whole pack for distortion: leaving GEOMETRY and SCALE set is what used to keep a
442 * projection change and a zoom running after their correction had been switched off. */
443 p->modify_flags &= ~_lens_axis_flags(axis);
444 /* The source bits stay cleared, so an axis switched off and on again comes back as the
445 * database rather than as whatever it was before. */
446 }
447 else
448 {
449 p->modify_flags |= _lens_axis_flags(axis);
450 p->modify_flags |= ((int)source & DT_LENS_SOURCE_BITS) << _lens_axis_shift(axis);
451 }
452
453 /* Kept in step rather than left to rot: an older Ansel reading this edit sees only
454 * tca_override, and it should still see the truth. */
456 p->tca_override = (source == DT_LENS_SOURCE_MANUAL) ? TRUE : FALSE;
457}
458
460static inline gboolean _lens_source_is(const dt_iop_lensfun_params_t *p,
461 const dt_lens_axis_t axis,
462 const dt_lens_source_t source)
463{
464 return _lens_source_get(p, axis) == source;
465}
466
468static inline gboolean _lens_axis_enabled(const dt_iop_lensfun_params_t *p,
469 const dt_lens_axis_t axis)
470{
472}
473
482static inline gboolean _lens_flags_move_pixels(const int modify_flags)
483{
484 return (modify_flags & (DT_LENS_MODIFY_TCA | DT_LENS_MODIFY_DISTORTION_PACK)) != 0;
485}
486
498static inline gboolean _lens_source_is_library_served(const dt_lens_source_t source)
499{
500 return source == DT_LENS_SOURCE_LENSFUN || source == DT_LENS_SOURCE_MANUAL
501 || source == DT_LENS_SOURCE_EMBEDDED;
502}
503
505static inline gboolean _lens_flags_have_axis(const int modify_flags, const dt_lens_axis_t axis)
506{
507 return (modify_flags & _lens_axis_presence_bit(axis)) != 0;
508}
509
521
522
523/* ===================================================================================== */
524
537{
538 if(IS_NULL_PTR(self->dev)) return FALSE;
540
541 switch(axis)
542 {
544 case DT_LENS_AXIS_TCA: return (axes & LS_ENABLE_TCA) != 0;
546 default: return FALSE;
547 }
548}
549
569
570/* Defined with the widgets they act on, at the bottom of the GUI section. Declared here
571 * because every setter that changes what the database can match -- the camera, the lens --
572 * has to say so, and those sit above them. */
575
583
584/* ---------------------------------------------------------------------------------------
585 * The LensSerious calibration database, latched BESIDE liblensfun's rather than replacing
586 * it.
587 *
588 * Every lookup below is answered twice -- once by liblensfun, once by LensSerious -- and
589 * both answers are printed. lensfun keeps authoring the pixels; nothing here changes what
590 * is rendered. The point is to run the real GUI on real images and read the log, because
591 * the disagreements that matter are not the ones a synthetic harness reaches: the harness
592 * walks the database, and this walks whatever a user's EXIF actually says, spelled however
593 * the camera spelled it.
594 *
595 * Reading is lock-free by construction -- `mode=ro&immutable=1` with SQLITE_OPEN_NOMUTEX,
596 * so SQLite takes no file lock, no shared-memory segment and no mutex. The price is ONE
597 * HANDLE PER THREAD, so the handle is thread-local and closed by its destructor when the
598 * thread ends, or by cleanup_global() for the thread unloading the modules. Threads that never
599 * touch a lens never open it.
600 *
601 * The one-entry caches beside it stand in for the two process-wide memo hash tables:
602 * commit_params() resolves the camera and the lens on every pipe resync, for every pipe,
603 * and asks the SAME question every time -- an image's camera and lens do not change while
604 * it is open. A per-thread cache of the last answer serves that exactly, with no lock and
605 * no unbounded growth, where a shared table would need a mutex back.
606 * ------------------------------------------------------------------------------------ */
607typedef struct _ls_tls_t
608{
610 gboolean tried;
611
612 char cam_key[512];
613 ls_camera_t cam;
614 gboolean cam_found;
615 gboolean cam_cached;
616
617 char lens_key[512];
618 long long lens_id;
619 gboolean lens_cached;
621
622/* Closed when the thread that opened it exits, which is the whole reason this is a GPrivate
623 * and not a plain __thread pointer: the handle has to be RELEASED, and nothing else in C
624 * runs code at thread exit. iop/drawlayer.c holds its per-thread scratch buffers the same
625 * way, for the same reason. The main thread ends in exit(), which runs no such destructor:
626 * cleanup_global() releases the block of the thread that unloads the modules. */
627static void _ls_tls_free(gpointer data)
628{
629 _ls_tls_t *tls = (_ls_tls_t *)data;
630 if(IS_NULL_PTR(tls)) return;
631 if(!IS_NULL_PTR(tls->db)) ls_db_close(tls->db);
632 dt_free(tls);
633}
634
636
640{
642 if(!IS_NULL_PTR(tls)) return tls;
643
644 tls = (_ls_tls_t *)g_malloc0(sizeof(_ls_tls_t));
645 if(IS_NULL_PTR(tls)) return NULL;
646 /* The only field whose zeroed value is not the right one: -1 is "no lens", 0 is a
647 * perfectly good row id. */
648 tls->lens_id = -1;
650 return tls;
651}
652
668static void _lens_report_db_failure(const char *path, const ls_db_open_status_t status,
669 const int found_version, const char *detail)
670{
671 const char *reason = (!IS_NULL_PTR(detail) && detail[0]) ? detail : "no further detail";
672
673 switch(status)
674 {
676 dt_print(DT_DEBUG_PIPE, "[lens] no `%s'\n", path);
677 break;
678
680 /* Printed with whatever refused it, because it is not always the file: the path goes
681 * through a URI conversion before SQLite sees it, and on Windows a readable file got
682 * lost in there while "check its permissions" sent its owner looking at permissions
683 * that were fine. The detail says which of the two happened. */
685 "[lens] `%s' exists but could not be read: %s. Check its permissions, and "
686 "that it is not truncated\n", path, reason);
687 break;
688
690 /* The one that actually happens, and the one the old message hid: a lenses.db left
691 * behind in a prefix by an earlier install. The build only installs the file when it
692 * produced one, so a rebuild that could not run the importer leaves the old file in
693 * place and the new binary refuses it. */
695 "[lens] `%s' is a lens database of schema v%d, and this Ansel reads v%d. It "
696 "is almost certainly left over from an older install: rebuild and reinstall "
697 "so the file is replaced, or delete it if it is a stale copy in your "
698 "configuration directory.\n",
700 break;
701
702 case LS_DB_OPEN_OK:
703 default:
704 break;
705 }
706}
707
708static ls_db_t *_ls_db(void)
709{
711 if(IS_NULL_PTR(tls)) return NULL;
712
713 if(tls->tried) return tls->db;
714 tls->tried = TRUE;
715
716 char dir[DT_PATH_MAX] = { 0 };
717 char path[DT_PATH_MAX] = { 0 };
718 char config_path[DT_PATH_MAX] = { 0 };
720 int config_version = -1;
721 char config_detail[256] = { 0 };
722
723 dt_loc_get_user_config_dir(dir, sizeof(dir));
724 dt_concat_path_file(config_path, dir, "lenses.db");
726 sizeof(config_detail));
727
729 int data_version = -1;
730 char data_detail[256] = { 0 };
731 if(IS_NULL_PTR(tls->db))
732 {
733 dt_loc_get_datadir(dir, sizeof(dir));
734 dt_concat_path_file(path, dir, "lenses.db");
736 sizeof(data_detail));
737 }
738
739 /* Say WHICH failure it was, per path. All three used to print "no calibration database",
740 * so a user whose file sat exactly where the message said it had looked was told to go
741 * find it again -- when what they actually had was a database from an older install,
742 * perfectly readable and built for a schema this Ansel does not read. */
743 if(IS_NULL_PTR(tls->db))
744 {
748 "[lens] no calibration database, so no lens correction is available.\n");
749 }
750 else
751 {
752 /* A config-directory database that exists and was refused is worth one line even when
753 * the shipped one saved the day: it is tried FIRST, so the user believes it is the one
754 * in use, and ansel-lens-db-update is what put it there. */
757
758 dt_print(DT_DEBUG_PIPE, "[lens] opened `%s' (schema v%d)\n",
761 }
762
763 return tls->db;
764}
765
767static gboolean _ls_find_camera(const char *maker, const char *model, ls_camera_t *out)
768{
769 if(IS_NULL_PTR(model) || !model[0]) return FALSE;
770 /* _ls_db() has already established that this thread has a cache block; it cannot have
771 * returned a database without one. */
773 ls_db_t *db = _ls_db();
774 if(IS_NULL_PTR(db) || IS_NULL_PTR(tls)) return FALSE;
775
776 char key[512];
777 snprintf(key, sizeof(key), "%s\x1f%s", maker ? maker : "", model);
778 if(tls->cam_cached && !strcmp(key, tls->cam_key))
779 {
780 if(tls->cam_found) *out = tls->cam;
781 return tls->cam_found ? TRUE : FALSE;
782 }
783
784 ls_camera_t cam;
785 /* A miss is cached too: it costs a lookup to establish and it will not change. */
786 const gboolean found = (ls_db_find_camera(db, maker, model, &cam) == 1) ? TRUE : FALSE;
787
788 g_strlcpy(tls->cam_key, key, sizeof(tls->cam_key));
789 tls->cam = cam;
790 tls->cam_found = found;
791 tls->cam_cached = TRUE;
792
793 if(found) *out = cam;
794 return found;
795}
796
829static long long _ls_find_lens(long long mount_id, float crop, float focal,
830 const char *lens_name)
831{
832 if(IS_NULL_PTR(lens_name) || !lens_name[0]) return -1;
834 ls_db_t *db = _ls_db();
835 if(IS_NULL_PTR(db) || IS_NULL_PTR(tls)) return -1;
836
837 char key[512];
838 snprintf(key, sizeof(key), "%lld\x1f%.4f\x1f%.4f\x1f%s", mount_id, (double)crop,
839 (double)focal, lens_name);
840 if(tls->lens_cached && !strcmp(key, tls->lens_key)) return tls->lens_id;
841
842 /* Several candidates rather than one, because the best-scoring name may be a lens this
843 * picture cannot have come through, and the next one down may be exactly right. */
844 ls_db_match_t m[8];
845 const int n = ls_db_match_lens(db, NULL, lens_name, mount_id, crop, m,
846 (int)(sizeof(m) / sizeof(*m)));
847 long long id = -1;
848 for(int i = 0; i < n; i++)
849 {
850 ls_lens_t cand;
851 if(ls_db_lens_by_id(db, m[i].lens_id, &cand) != 1) continue;
852
853 /* A hair of tolerance: EXIF focals are rounded, and a prime's range is a single value
854 * it must still match. Ranges are ordered by the importer. */
855 if(focal > 0.f
856 && (focal < cand.min_focal - 0.05f || focal > cand.max_focal + 0.05f))
857 continue;
858
859 id = m[i].lens_id;
860 break;
861 }
862
863 g_strlcpy(tls->lens_key, key, sizeof(tls->lens_key));
864 tls->lens_id = id;
865 tls->lens_cached = TRUE;
866 return id;
867}
868
895
908static inline gboolean _lens_data_available(const dt_iop_lensfun_data_t *d)
909{
910 return d->knots_have || (d->ls_have && d->crop > 0.f);
911}
912
913
914const char *name()
915{
916 return _("_lens correction");
917}
918
919const char *aliases()
920{
921 return _("vignette|chromatic aberrations|distortion");
922}
923
924const char **description(struct dt_iop_module_t *self)
925{
926 return dt_iop_set_description(self, _("correct lenses optical flaws"),
927 _("corrective"),
928 _("linear, RGB, scene-referred"),
929 _("geometric and reconstruction, RGB"),
930 _("linear, RGB, scene-referred"));
931}
932
933
935{
936 return IOP_GROUP_REPAIR;
937}
938
940{
941 return IOP_TAG_DISTORT;
942}
943
948
953
954int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version,
955 void *new_params, const int new_version)
956{
957 if(old_version == 2 && new_version == 5)
958 {
959 // legacy params of version 2; version 1 comes from ancient times and seems to be forgotten by now
960 typedef struct
961 {
962 int modify_flags;
963 int inverse;
964 float scale;
965 float crop;
966 float focal;
967 float aperture;
968 float distance;
969 dt_lens_type_t target_geom;
970 char camera[52];
971 char lens[52];
972 int tca_override;
973 float tca_r, tca_b;
975
979
980 *n = *d; // start with a fresh copy of default parameters
981
982 n->modify_flags = o->modify_flags;
983 n->inverse = o->inverse;
984 n->scale = o->scale;
985 n->crop = o->crop;
986 n->focal = o->focal;
987 n->aperture = o->aperture;
988 n->distance = o->distance;
989 n->target_geom = o->target_geom;
990 n->tca_override = o->tca_override;
991 g_strlcpy(n->camera, o->camera, sizeof(n->camera));
992 g_strlcpy(n->lens, o->lens, sizeof(n->lens));
993 n->modified = 1;
994
995 // old versions had R and B swapped
996 n->tca_r = o->tca_b;
997 n->tca_b = o->tca_r;
998
999 return 0;
1000 }
1001 if(old_version == 3 && new_version == 5)
1002 {
1003 typedef struct
1004 {
1005 int modify_flags;
1006 int inverse;
1007 float scale;
1008 float crop;
1009 float focal;
1010 float aperture;
1011 float distance;
1012 dt_lens_type_t target_geom;
1013 char camera[128];
1014 char lens[128];
1015 int tca_override;
1016 float tca_r, tca_b;
1018
1022
1023 *n = *d; // start with a fresh copy of default parameters
1024
1025 /* The whole OLD struct, sized from the old struct. It used to be sized as the new one
1026 * minus an int, which is the same number only for as long as v5 has exactly one field
1027 * more than v3 -- add a second and this reads off the end of the caller's buffer. */
1028 memcpy(n, o, sizeof(*o));
1029
1030 // one more parameter and changed parameters in case we autodetect
1031 n->modified = 1;
1032
1033 // old versions had R and B swapped
1034 n->tca_r = o->tca_b;
1035 n->tca_b = o->tca_r;
1036
1037 return 0;
1038 }
1039
1040 if(old_version == 4 && new_version == 5)
1041 {
1042 typedef struct
1043 {
1044 int modify_flags;
1045 int inverse;
1046 float scale;
1047 float crop;
1048 float focal;
1049 float aperture;
1050 float distance;
1051 dt_lens_type_t target_geom;
1052 char camera[128];
1053 char lens[128];
1054 int tca_override;
1055 float tca_r, tca_b;
1056 int modified;
1058
1062
1063 *n = *d; // start with a fresh copy of default parameters
1064
1065 memcpy(n, o, sizeof(dt_iop_lensfun_params_t));
1066
1067 // old versions had R and B swapped
1068 n->tca_r = o->tca_b;
1069 n->tca_b = o->tca_r;
1070
1071 return 0;
1072 }
1073
1074 return 1;
1075}
1076
1077static char *_lens_sanitize(const char *orig_lens)
1078{
1079 const char *found_or = strstr(orig_lens, " or ");
1080 const char *found_parenthesis = strstr(orig_lens, " (");
1081
1083 {
1084 size_t pos_or = (size_t)(found_or - orig_lens);
1085 size_t pos_parenthesis = (size_t)(found_parenthesis - orig_lens);
1086 size_t pos = pos_or < pos_parenthesis ? pos_or : pos_parenthesis;
1087
1088 if(pos > 0)
1089 {
1090 char *new_lens = (char *)malloc(pos + 1);
1091
1092 strncpy(new_lens, orig_lens, pos);
1093 new_lens[pos] = '\0';
1094
1095 return new_lens;
1096 }
1097 else
1098 {
1099 char *new_lens = strdup(orig_lens);
1100 return new_lens;
1101 }
1102 }
1103 else
1104 {
1105 char *new_lens = strdup(orig_lens);
1106 return new_lens;
1107 }
1108}
1109
1125static int get_modifier(int *mods_done, int w, int h, const dt_iop_lensfun_data_t *d,
1128{
1129 memset(mod, 0, sizeof(*mod));
1130 if(mods_done) *mods_done = 0;
1131 /* A maker's own profile needs no database entry and no crop factor -- it describes THIS
1132 * body and lens, and it arrived in the file. Refusing it for want of a database lens is
1133 * how the embedded path would have been unreachable on exactly the bodies that carry
1134 * one and are not calibrated upstream. */
1135 if(!_lens_data_available(d)) return 0;
1136
1137 int mods_todo = d->modify_flags & mods_filter;
1138
1139 /* Drop any axis whose source this build cannot serve, so an unknown source from some
1140 * future Ansel visibly does nothing rather than silently correcting from the database.
1141 * Filtering here, at the one place that decides what to ask a resolver for, means the
1142 * rest of the module never re-derives it. */
1144 {
1145 const dt_lens_source_t source = _lens_source_decode(d->modify_flags, d->tca_override, axis);
1146 /* The whole pack, so switching distortion to another source stops the projection change
1147 * and the scaling with it -- they are one correction, and leaving them running was what
1148 * kept geometry applying after its control had been hidden. */
1150 }
1151
1152 int want = 0;
1158
1159 const int reverse = force_inverse ? !d->inverse : d->inverse;
1160
1161 /* Which resolver, decided by the distortion axis because that is the one that owns the
1162 * coordinate system: a maker's table indexes radius against the half diagonal, the
1163 * database against lensfun's short side, and a single modifier can only be in one of
1164 * them. Vignetting is not bound by that -- it is a gain, resolved separately below. */
1166 = _lens_source_decode(d->modify_flags, d->tca_override, DT_LENS_AXIS_DISTORTION);
1167 const gboolean geom_embedded = (geom_source == DT_LENS_SOURCE_EMBEDDED) && d->knots_have;
1168
1169 /* The one remaining way to end up on the database while the user asked for the file: the
1170 * table did not resolve. commit_params has already said why, once, so this stays quiet --
1171 * it runs per pipe per frame and would drown the reason it is reporting. */
1172
1173 int got;
1174 if(geom_embedded)
1175 {
1176 /* The maker measured the lens as it shipped, so there is no projection change to make
1177 * and the scale to use is the one their own profile asks for. */
1178 /* The maker's own autoscale AND the user's slider, composed. The profile ships the
1179 * factor that just clears the borders it leaves; the slider is what the user wants on
1180 * top of that, and passing only the first left the slider inert in this mode -- a
1181 * control that moves and changes nothing. */
1182 const float knots_scale = d->knots_scale * ((d->scale > 0.f) ? d->scale : 1.f);
1183
1184 /* Ask the table for chromatic aberration only if that axis actually chose it. The
1185 * maker's curve carries distortion and CA together, so asking for both when CA was set
1186 * to the database or to typed values would apply the maker's aberration on top of the
1187 * other one -- over-correcting the fringing by exactly the maker's amount, with the
1188 * panel showing a source the pixels never used. Asked for distortion alone, the table
1189 * hands back pure geometry and the chosen TCA model runs after it. */
1191 if(_lens_source_decode(d->modify_flags, d->tca_override, DT_LENS_AXIS_TCA)
1194
1195 got = ls_modifier_init_knots(mod, &d->ls_knots, w, h, knots_scale, knot_want, reverse);
1196
1197 /* TCA from somewhere else rides on the table's geometry. ls_modifier_init_knots() only
1198 * fills the knot tables, so the polynomial the database resolved -- or the linear one
1199 * _lens_build_data() synthesised from the user's two numbers -- has to be put in.
1200 *
1201 * ONLY THIS DIRECTION. The reverse -- a database distortion wearing the maker's
1202 * aberration -- is not implemented and is not an oversight:
1203 *
1204 * - physically it is two calibrations of the same lens applied to each other. The
1205 * maker measured their aberration as a departure from THEIR geometry, so it is only
1206 * the right departure when that geometry is the one in force;
1207 * - mechanically the table has no separate aberration to lift out. Distortion and CA
1208 * are one per-channel curve; green is the geometry and the other two are defined
1209 * relative to it, so "the CA alone" would be the ratio knot_c[c]/knot_c[1] resampled
1210 * onto the database's radius axis -- which is a different normalization again (half
1211 * short side against half diagonal), needing the radius conversion factor that
1212 * ls_modifier_set_projection() documents.
1213 *
1214 * If it is ever wanted: add LS_EVAL_TCA_KNOTS carrying those ratios plus that factor,
1215 * and expect to answer the physical objection first. _lens_rebuild_axis_row() withdraws
1216 * the row meanwhile, so the combination cannot be selected and then quietly ignored. */
1217 if((want & LS_ENABLE_TCA) && !(knot_want & LS_ENABLE_TCA) && d->ls_have)
1218 {
1220 if(ls_modifier_init(&tca_mod, &d->ls_lens, d->crop, w, h, d->focal, d->aperture,
1221 d->distance, 1.f, (int)d->target_geom, LS_ENABLE_TCA, reverse)
1222 & LS_ENABLE_TCA)
1223 {
1224 mod->tca = tca_mod.tca;
1225 mod->enabled |= LS_ENABLE_TCA;
1226 got |= LS_ENABLE_TCA;
1227 }
1228 }
1229
1230 /* The projection, put back on top of the maker's table.
1231 *
1232 * The table cannot supply it -- it describes the lens in the projection it shipped
1233 * with -- but the database entry matched alongside knows the lens's type, and that is
1234 * all the stage needs besides a focal. Without this, asking for a fisheye to be
1235 * rectilinear did nothing whenever distortion came from the file, which is the one
1236 * case where the two sources visibly disagreed about what the module could do.
1237 *
1238 * The crop here is the SHOOTING camera's, unlike the database path's: this modifier
1239 * normalizes radius against the half diagonal of the frame in hand, so that is the
1240 * sensor its projection focal has to be expressed against. */
1241 if((want & LS_ENABLE_GEOMETRY) && d->ls_have && d->crop > 0.f && d->focal > 0.f)
1242 {
1243 if(ls_modifier_set_projection(mod, (int)d->ls_lens.type, (int)d->target_geom,
1244 d->focal, d->crop))
1246 }
1247 }
1248 else
1249 got = ls_modifier_init(mod, &d->ls_lens, d->crop, w, h, d->focal, d->aperture,
1250 d->distance, d->scale, (int)d->target_geom, want, reverse);
1251
1252 int done = 0;
1258
1259 /* A projection change LensSerious will not serve -- panoramic or equirectangular on
1260 * either side, which map x and y differently and are not radially expressible -- is
1261 * reported as not done rather than approximated. */
1262 if(mod->geometry_unsupported) done &= ~DT_LENS_MODIFY_GEOMETRY;
1263
1264 /* Vignetting, resolved on its own when it does not come from the same place as the
1265 * geometry. That combination is not exotic: an Olympus body embeds distortion and lateral
1266 * CA and no falloff at all, so "geometry from the file, vignetting from the database" is
1267 * the ordinary case for that maker rather than a corner of one.
1268 *
1269 * It works because the two halves of the correction never share a number. Vignetting
1270 * reads its own scale, its own centre and its own model, so a resolver that normalises
1271 * radius differently cannot disturb it -- which is exactly what
1272 * ls_eval_adopt_vignetting() relies on when the two are put back into one block. */
1273 if(vig_mod)
1274 {
1276 = _lens_source_decode(d->modify_flags, d->tca_override, DT_LENS_AXIS_VIGNETTING);
1277 const gboolean vig_embedded = (vig_source == DT_LENS_SOURCE_EMBEDDED) && d->knots_have;
1278 const gboolean vig_wanted = (mods_todo & DT_LENS_MODIFY_VIGNETTING) != 0;
1279
1281 {
1282 /* Same resolver, or nothing asked for: the main modifier's own state answers. When
1283 * the axis is off, `want` never carried vignetting, so this copy carries none either
1284 * -- resolving one here anyway was the bug: the GPU path grafts whatever this block
1285 * holds into its single eval block and the fused kernels apply what is enabled there,
1286 * so a falloff nobody asked for came back through the graft with the axis OFF. */
1287 *vig_mod = *mod;
1288 }
1289 else if(vig_embedded)
1290 ls_modifier_init_knots(vig_mod, &d->ls_knots, w, h, 1.f, LS_ENABLE_VIGNETTING, reverse);
1291 else
1292 ls_modifier_init(vig_mod, &d->ls_lens, d->crop, w, h, d->focal, d->aperture,
1293 d->distance, 1.f, (int)d->target_geom, LS_ENABLE_VIGNETTING, reverse);
1294
1295 /* The truth about vignetting now lives in vig_mod, whichever resolver produced it, so
1296 * the reported axis must be read from THERE. Reading it from the main modifier is how
1297 * the flagship hybrid silently lost its falloff: an Olympus table has no vignetting
1298 * knots, so the main (knots) resolver reported the axis not-done, the database
1299 * vignetting sat correctly resolved in vig_mod -- and every caller gates the falloff
1300 * on the done bit, so it was never applied. */
1301 if(vig_wanted && (vig_mod->enabled & LS_ENABLE_VIGNETTING))
1303 else
1305 }
1306
1307 if(mods_done) *mods_done = done;
1308 return done != 0;
1309}
1310
1311static inline void _lens_fill_vignette_row(float *const buf, const int width, const int ch)
1312{
1314 {
1315 const dt_aligned_pixel_simd_t half = dt_simd_set1(0.5f);
1316 for(int x = 0; x < width; x++) dt_store_simd_aligned(buf + (size_t)x * ch, half);
1317 }
1318 else
1319 {
1320 for(int k = 0; k < ch * width; k++) buf[k] = 0.5f;
1321 }
1322}
1323
1324/* Why do we care about being a monochrome image or not?
1325 The lensfun library does not have an algorithm for distortion or tca correction specialized for monochrome images,
1326 the builtin correction works with subtle differences for the color channels leading to some colorizing of the images.
1327 How is this fixed here:
1328 Monochrome images (from pure monochrome cameras or cameras with the color filter removed from the sensor) have
1329 all three rgb colors set to the same value by the demosaicer.
1330 Looking through lensfun code & docs the ApplySubpixelGeometryDistortion algorithm makes assumptions from given
1331 coeffs how far data are displaced for the different wavelengths of light.
1332 As green / Y channel is the most centric i took that as the canonical value instead of taking the mean.
1333*/
1334
1337 const void *const ivoid, void *const ovoid)
1338{
1339 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1340 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1341 const dt_iop_lensfun_data_t *const d = (dt_iop_lensfun_data_t *)piece->data;
1342
1343 const int ch = piece->dsc_in.channels;
1344 const int ch_width = ch * roi_in->width;
1345 const int mask_display = pipe->mask_display;
1346
1347
1349 {
1350 dt_iop_image_copy_by_size((float*)ovoid, (float*)ivoid, roi_out->width, roi_out->height, ch);
1351 return 0;
1352 }
1353
1354 const gboolean raw_monochrome = dt_image_is_monochrome(&self->dev->image_storage);
1355 const int used_lf_mask = _lens_mask_for_mono(raw_monochrome);
1356
1357 const float orig_w = roi_in->scale * piece->buf_in.width, orig_h = roi_in->scale * piece->buf_in.height;
1358
1359 int modflags;
1360 ls_modifier_t modifier;
1362 get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, FALSE, &modifier, &vig_modifier);
1363 dt_print(DT_DEBUG_PIPE, "[lens] resolved 0x%x of 0x%x requested (%d dist, %d tca, %d vig"
1364 " calibrations, crop %.4f, focal %.1f)\n", modflags, d->modify_flags,
1365 d->ls_lens.n_dist, d->ls_lens.n_tca, d->ls_lens.n_vig, (double)d->crop,
1366 (double)d->focal);
1367
1368
1369 const struct dt_interpolation *const interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF_WARP);
1370
1371 /* Vignetting is folded into the resampling loops below rather than run as a pass of its
1372 * own over a whole copy of the frame. ls_eval_vignette_factor() answers 1 when vignetting
1373 * is not enabled, so the loops need no second branch for it.
1374 *
1375 * Which FRAME the falloff lives in depends on the direction. Correcting, it belongs to
1376 * the source, so each channel takes the factor at ITS OWN source coordinate -- exactly
1377 * what the two-pass did, which darkened the input and then let each channel sample its
1378 * own position in it. Reversing, it is being put back onto the frame being produced, so
1379 * it is evaluated at the destination. */
1380 /* Flattened from the VIGNETTING modifier, not the geometry one. They are usually the same
1381 * object; they differ when the two axes take different sources, and this is where that
1382 * costs nothing -- the falloff already had a block of its own. */
1383 ls_eval_t vp;
1386
1387 if(d->inverse)
1388 {
1389 // reverse direction (useful for renderings)
1391 {
1392 // acquire temp memory for distorted pixel coords
1393 const size_t bufsize = (size_t)roi_out->width * 2 * 3;
1394
1395 size_t padded_bufsize;
1397 if(IS_NULL_PTR(buf)) return 1;
1398
1399#ifdef _OPENMP
1400#pragma omp parallel for default(none) \
1401 firstprivate(roi_out, roi_in, padded_bufsize, modifier, ch, d, buf, ovoid, ivoid, ch_width, interpolation, raw_monochrome, mask_display, have_vig, vp)
1402#endif
1403 for(int y = 0; y < roi_out->height; y++)
1404 {
1405 float *bufptr = (float*)dt_get_perthread(buf, padded_bufsize);
1406 ls_modifier_apply_subpixel_geometry(&modifier, roi_out->x, roi_out->y + y, roi_out->width, 1, bufptr);
1407
1408 // reverse transform the global coords from lf to our buffer
1409 float *out = ((float *)ovoid) + (size_t)y * roi_out->width * ch;
1410 for(int x = 0; x < roi_out->width; x++, bufptr += 6, out += ch)
1411 {
1412 dt_aligned_pixel_simd_t pixel = { 0.f };
1413 for(int c = 0; c < 3; c++)
1414 {
1415 if(d->do_nan_checks && (!isfinite(bufptr[c * 2]) || !isfinite(bufptr[c * 2 + 1])))
1416 {
1417 pixel[c] = 0.0f;
1418 continue;
1419 }
1420
1421 const float *const inptr = (const float *const)ivoid + (size_t)c;
1422 const float pi0 = fmaxf(fminf(bufptr[c * 2] - roi_in->x, roi_in->width - 1.0f), 0.0f);
1423 const float pi1 = fmaxf(fminf(bufptr[c * 2 + 1] - roi_in->y, roi_in->height - 1.0f), 0.0f);
1424 pixel[c] = dt_interpolation_compute_sample(interpolation, inptr, pi0, pi1, roi_in->width,
1425 roi_in->height, ch, ch_width);
1426 }
1427
1428 if(have_vig)
1429 {
1430 /* Reversing: the falloff belongs to the frame being produced. */
1431 const float v = ls_eval_vignette_factor(&vp, (float)(roi_out->x + x),
1432 (float)(roi_out->y + y));
1433 for(int c = 0; c < 3; c++) pixel[c] *= v;
1434 }
1435 if(raw_monochrome) pixel[0] = pixel[2] = pixel[1];
1436
1437 if(mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK)
1438 {
1439 if(d->do_nan_checks && (!isfinite(bufptr[2]) || !isfinite(bufptr[3])))
1440 {
1441 pixel[3] = 0.0f;
1442 }
1443 else
1444 {
1445 // take green channel distortion also for alpha channel
1446 const float *const inptr = (const float *const)ivoid + (size_t)3;
1447 const float pi0 = fmaxf(fminf(bufptr[2] - roi_in->x, roi_in->width - 1.0f), 0.0f);
1448 const float pi1 = fmaxf(fminf(bufptr[3] - roi_in->y, roi_in->height - 1.0f), 0.0f);
1449 pixel[3] = dt_interpolation_compute_sample(interpolation, inptr, pi0, pi1, roi_in->width,
1450 roi_in->height, ch, ch_width);
1451 }
1452 }
1453
1454 // Alpha too: it is 0 unless the mask is displayed, and left unwritten it would be
1455 // whatever the output buffer last held.
1457 else for(int c = 0; c < ch; c++) out[c] = pixel[c];
1458 }
1459 }
1461 }
1462 else
1463 {
1464 dt_iop_image_copy_by_size((float*)ovoid, (float*)ivoid, roi_out->width, roi_out->height, ch);
1465
1466 /* Nothing moved, so there was no resampling loop to fold the falloff into. */
1467 if(have_vig)
1468 {
1469 __OMP_PARALLEL_FOR__(firstprivate(modifier, ovoid, roi_out, ch))
1470 for(int y = 0; y < roi_out->height; y++)
1471 {
1472 float *out = ((float *)ovoid) + (size_t)y * roi_out->width * ch;
1473 ls_modifier_apply_vignetting(&modifier, roi_out->x, roi_out->y + y, roi_out->width, 1,
1474 out, (int)((ch * roi_out->width) * sizeof(float)));
1475 }
1476 }
1477 }
1478 }
1479 else // correct distortions:
1480 {
1481 /* No copy of the input, and no separate vignetting pass over it. This used to
1482 * duplicate the whole frame -- 387 MB for a 24 Mpx RGBA buffer -- darken the copy, and
1483 * resample from it. The falloff is a per-source-pixel gain, so folding it into the
1484 * resampling loop below gives the same answer while reading the caller's own buffer. */
1485
1487 {
1488 // acquire temp memory for distorted pixel coords
1489 const size_t buf2size = (size_t)roi_out->width * 2 * 3;
1490 size_t padded_buf2size;
1492 if(IS_NULL_PTR(buf2)) return 1;
1493
1494
1495#ifdef _OPENMP
1496#pragma omp parallel for default(none) \
1497 firstprivate(roi_out, roi_in, ovoid, ivoid, ch, padded_buf2size, modifier, mask_display, raw_monochrome, interpolation, ch_width, d, buf2, have_vig, vp)
1498#endif
1499 for(int y = 0; y < roi_out->height; y++)
1500 {
1501 float *buf2ptr = (float*)dt_get_perthread(buf2, padded_buf2size);
1502 ls_modifier_apply_subpixel_geometry(&modifier, roi_out->x, roi_out->y + y, roi_out->width, 1, buf2ptr);
1503 // reverse transform the global coords from lf to our buffer
1504 float *out = ((float *)ovoid) + (size_t)y * roi_out->width * ch;
1505 for(int x = 0; x < roi_out->width; x++, buf2ptr += 6, out += ch)
1506 {
1507 dt_aligned_pixel_simd_t pixel = { 0.f };
1508 for(int c = 0; c < 3; c++)
1509 {
1510 if(d->do_nan_checks && (!isfinite(buf2ptr[c * 2]) || !isfinite(buf2ptr[c * 2 + 1])))
1511 {
1512 pixel[c] = 0.0f;
1513 continue;
1514 }
1515
1516 const float *bufptr = ((const float *)ivoid) + c;
1517 const float pi0 = fmaxf(fminf(buf2ptr[c * 2] - roi_in->x, roi_in->width - 1.0f), 0.0f);
1518 const float pi1 = fmaxf(fminf(buf2ptr[c * 2 + 1] - roi_in->y, roi_in->height - 1.0f), 0.0f);
1519 pixel[c] = dt_interpolation_compute_sample(interpolation, bufptr, pi0, pi1, roi_in->width,
1520 roi_in->height, ch, ch_width);
1521 /* Correcting: the falloff belongs to the source, so each channel takes it at
1522 * its own source coordinate -- which is what sampling an already-darkened input
1523 * amounted to. */
1524 if(have_vig)
1525 pixel[c] *= ls_eval_vignette_factor(&vp, buf2ptr[c * 2], buf2ptr[c * 2 + 1]);
1526 }
1527 if(raw_monochrome) pixel[0] = pixel[2] = pixel[1];
1528 if(mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK)
1529 {
1530 if(d->do_nan_checks && (!isfinite(buf2ptr[2]) || !isfinite(buf2ptr[3])))
1531 {
1532 pixel[3] = 0.0f;
1533 }
1534 else
1535 {
1536 // take green channel distortion also for alpha channel
1537 const float *bufptr = ((const float *)ivoid) + 3;
1538 const float pi0 = fmaxf(fminf(buf2ptr[2] - roi_in->x, roi_in->width - 1.0f), 0.0f);
1539 const float pi1 = fmaxf(fminf(buf2ptr[3] - roi_in->y, roi_in->height - 1.0f), 0.0f);
1540 pixel[3] = dt_interpolation_compute_sample(interpolation, bufptr, pi0, pi1, roi_in->width,
1541 roi_in->height, ch, ch_width);
1542 }
1543 }
1544
1545 // Alpha too: it is 0 unless the mask is displayed, and left unwritten it would be
1546 // whatever the output buffer last held.
1548 else for(int c = 0; c < ch; c++) out[c] = pixel[c];
1549 }
1550 }
1552 }
1553 else
1554 {
1555 dt_iop_image_copy_by_size((float *)ovoid, (float *)ivoid, roi_out->width, roi_out->height, ch);
1556
1557 /* Nothing moved, so there was no resampling loop to fold the falloff into. */
1558 if(have_vig)
1559 {
1560 __OMP_PARALLEL_FOR__(firstprivate(modifier, ovoid, roi_in, ch))
1561 for(int y = 0; y < roi_in->height; y++)
1562 {
1563 float *out = ((float *)ovoid) + (size_t)ch * roi_in->width * y;
1564 ls_modifier_apply_vignetting(&modifier, roi_in->x, roi_in->y + y, roi_in->width, 1, out,
1565 (int)((ch * roi_in->width) * sizeof(float)));
1566 }
1567 }
1568 }
1569 }
1570
1571 /* No GUI state is written here. Which corrections apply is a property of the
1572 * camera/lens/params combination, not of a rendered frame -- the label is computed on the
1573 * GUI thread by _lens_corrections_available(). */
1574 return 0;
1575}
1576
1577#ifdef HAVE_OPENCL
1578
1579
1580int 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)
1581{
1582 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1583 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1585
1586 const gboolean raw_monochrome = dt_image_is_monochrome(&self->dev->image_storage);
1587 const int used_lf_mask = _lens_mask_for_mono(raw_monochrome);
1588
1589 cl_int err = -999;
1590
1592 ls_modifier_t modifier;
1593 /* Declared before the first `goto error`: C++ forbids jumping over an initialisation. */
1594 ls_eval_t p;
1595 gboolean have_eval = FALSE, do_geom = FALSE, do_vig = FALSE;
1596
1597 const int devid = pipe->devid;
1598 const int iwidth = roi_in->width;
1599 const int iheight = roi_in->height;
1600 const int owidth = roi_out->width;
1601 const int oheight = roi_out->height;
1602 const int roi_in_x = roi_in->x;
1603 const int roi_in_y = roi_in->y;
1604 const int roi_out_x = roi_out->x;
1605 const int roi_out_y = roi_out->y;
1606
1607 const float orig_w = roi_in->scale * piece->buf_in.width, orig_h = roi_in->scale * piece->buf_in.height;
1608
1609 size_t origin[] = { 0, 0, 0 };
1610 size_t oregion[] = { (size_t)owidth, (size_t)oheight, 1 };
1611 size_t isizes[] = { (size_t)ROUNDUPDWD(iwidth, devid), (size_t)ROUNDUPDHT(iheight, devid), 1 };
1612 size_t osizes[] = { (size_t)ROUNDUPDWD(owidth, devid), (size_t)ROUNDUPDHT(oheight, devid), 1 };
1613
1614 int modflags;
1615 int ldkernel = -1;
1616 /* Declared here, ahead of every `goto error`: C++ will not let one jump over an
1617 * initialisation. Resolved once below, after get_modifier() has settled modflags. */
1619
1621 {
1622 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, oregion);
1623 if(err != CL_SUCCESS) goto error;
1624 return TRUE;
1625 }
1626
1627 switch(interpolation->id)
1628 {
1630 ldkernel = gd->kernel_lens_distort_bilinear;
1631 break;
1633 ldkernel = gd->kernel_lens_distort_bicubic;
1634 break;
1636 ldkernel = gd->kernel_lens_distort_mitchell;
1637 break;
1638 default:
1639 return FALSE;
1640 }
1641
1642
1644 get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, FALSE, &modifier, &vig_modifier);
1645
1646 /* One kernel, in and out, in both directions.
1647 *
1648 * The correction crosses as an ls_eval_t -- 632 bytes of coefficients passed by value --
1649 * and each work-item evaluates its own source coordinates from it, so there is no
1650 * displacement map, no host buffer and no upload. Vignetting rides along inside the same
1651 * resampling pass rather than writing a whole intermediate image for the resampler to
1652 * read back.
1653 *
1654 * The direction lives in the block: ls_eval_map() reads p.reverse and composes the chain
1655 * accordingly, and _lens_devignette() places the falloff in the frame that direction puts
1656 * it in. So both directions are the same launch, which is why the branch that used to
1657 * distinguish them is gone. */
1658 have_eval = ls_eval_from_modifier(&modifier, &p) != 0;
1659
1660 /* One block serves both halves here, unlike the CPU path, so where the two axes took
1661 * different sources the falloff has to be grafted in from its own modifier. The two
1662 * halves of ls_eval_t share no field -- vignetting carries its own scale, centre and
1663 * model -- which is what makes the graft safe across resolvers that normalise radius
1664 * differently. A second block would be the obvious alternative and does not fit: 632
1665 * bytes each against the 1024 OpenCL 1.2 guarantees for a kernel's whole argument list. */
1666 if(have_eval)
1667 {
1668 ls_eval_t vp;
1670 }
1674
1675 if(do_geom)
1676 {
1677 /* Vignetting, if any, is applied inside this pass -- the kernel reads it out of p. */
1678 dt_opencl_set_kernel_arg(devid, ldkernel, 0, sizeof(cl_mem), (void *)&dev_in);
1679 dt_opencl_set_kernel_arg(devid, ldkernel, 1, sizeof(cl_mem), (void *)&dev_out);
1680 dt_opencl_set_kernel_arg(devid, ldkernel, 2, sizeof(int), (void *)&owidth);
1681 dt_opencl_set_kernel_arg(devid, ldkernel, 3, sizeof(int), (void *)&oheight);
1682 dt_opencl_set_kernel_arg(devid, ldkernel, 4, sizeof(int), (void *)&iwidth);
1683 dt_opencl_set_kernel_arg(devid, ldkernel, 5, sizeof(int), (void *)&iheight);
1684 dt_opencl_set_kernel_arg(devid, ldkernel, 6, sizeof(int), (void *)&roi_in_x);
1685 dt_opencl_set_kernel_arg(devid, ldkernel, 7, sizeof(int), (void *)&roi_in_y);
1686 dt_opencl_set_kernel_arg(devid, ldkernel, 8, sizeof(int), (void *)&roi_out_x);
1687 dt_opencl_set_kernel_arg(devid, ldkernel, 9, sizeof(int), (void *)&roi_out_y);
1688 dt_opencl_set_kernel_arg(devid, ldkernel, 10, sizeof(ls_eval_t), (void *)&p);
1689 dt_opencl_set_kernel_arg(devid, ldkernel, 11, sizeof(int), (void *)&(d->do_nan_checks));
1690 dt_opencl_set_kernel_arg(devid, ldkernel, 12, sizeof(int), (void *)&(raw_monochrome));
1692 if(err != CL_SUCCESS) goto error;
1693 }
1694 else if(do_vig)
1695 {
1696 /* Nothing moves, so there is nothing to resample: a dedicated pass costs one fetch per
1697 * pixel where the fused one would cost the resampler's full tap count for an identity
1698 * map. Which frame the falloff belongs to is the same question as above, and with no
1699 * geometry in play the two coincide. */
1700 const int vx = d->inverse ? roi_out_x : roi_in_x;
1701 const int vy = d->inverse ? roi_out_y : roi_in_y;
1702 const int vw = d->inverse ? owidth : iwidth;
1703 const int vh = d->inverse ? oheight : iheight;
1704 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 0, sizeof(cl_mem), (void *)&dev_in);
1705 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 1, sizeof(cl_mem), (void *)&dev_out);
1706 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 2, sizeof(int), (void *)&vw);
1707 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 3, sizeof(int), (void *)&vh);
1708 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 4, sizeof(int), (void *)&vx);
1709 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 5, sizeof(int), (void *)&vy);
1710 dt_opencl_set_kernel_arg(devid, gd->kernel_lens_vignette, 6, sizeof(ls_eval_t), (void *)&p);
1711 err = dt_opencl_enqueue_kernel_2d(devid, gd->kernel_lens_vignette,
1712 d->inverse ? osizes : isizes);
1713 if(err != CL_SUCCESS) goto error;
1714 }
1715 else
1716 {
1717 err = dt_opencl_enqueue_copy_image(devid, dev_in, dev_out, origin, origin, oregion);
1718 if(err != CL_SUCCESS) goto error;
1719 }
1720
1721 return TRUE;
1722
1723error:
1724 dt_print(DT_DEBUG_OPENCL, "[opencl_lens] couldn't enqueue kernel! %d\n", err);
1725 return FALSE;
1726}
1727#endif
1728
1730{
1731 /* CPU: in + out, and nothing else of image size.
1732 *
1733 * The whole-frame copy process() used to make -- to darken before resampling from it --
1734 * is gone with the separate vignetting pass: the falloff is folded into the resampling
1735 * loop, which now reads the caller's own input buffer. The displacement map is not a
1736 * whole-image temporary either: it is built a row at a time into a per-thread buffer of
1737 * width*6 floats, so it grows with the frame's WIDTH and the thread count rather than
1738 * its area -- ~2 MB for a 6000 px frame on 16 threads, against ~384 MB for one 24 Mpx
1739 * RGBA buffer. Counting it here would reserve memory nothing allocates.
1740 *
1741 * GPU: in + out, and nothing else at all -- one kernel reads the input and writes the
1742 * output, with vignetting folded into the same pass.
1743 *
1744 * Both figures used to be 4.5, meaning in + out + tmp + a six-float-per-pixel map buffer
1745 * (1.5x an RGBA one) that had to be built on the host and uploaded. The GPU path no
1746 * longer has that buffer -- each work-item evaluates its own coordinates from ~80 bytes
1747 * of coefficients passed as a kernel argument -- so reserving 1.5 image buffers for it
1748 * made the tile solver split frames that would have fitted whole.
1749 *
1750 * factor_cl and maxbuf_cl have to be set explicitly: dt_develop_tiling_t defaults them to
1751 * the CPU figures (develop/tiling.c), so a module that sets only `factor` silently
1752 * describes its GPU path with its CPU path's appetite. */
1753 tiling->factor = 2.0f; // in + out
1754 tiling->maxbuf = 1.0f;
1755 tiling->factor_cl = 2.0f; // in + out; no intermediate at all
1756 tiling->maxbuf_cl = 1.0f;
1757 tiling->overhead = 0;
1758 tiling->overlap = 4;
1759 tiling->xalign = 1;
1760 tiling->yalign = 1;
1761 return;
1762}
1763
1765 float *const __restrict points, size_t points_count)
1766{
1768 if(!_lens_data_available(d)) return 0;
1769
1770 const float orig_w = piece->buf_in.width, orig_h = piece->buf_in.height;
1771 int modflags;
1772
1773 const int used_lf_mask = _lens_mask_for_mono(dt_image_is_monochrome(&self->dev->image_storage));
1774
1775 ls_modifier_t modifier;
1776 get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, TRUE, &modifier, NULL);
1777
1779 {
1780 __OMP_PARALLEL_FOR__(firstprivate(points, points_count, modifier) if(points_count > 100))
1781 for(size_t i = 0; i < points_count * 2; i += 2)
1782 {
1783 float DT_ALIGNED_ARRAY buf[6];
1784 ls_modifier_apply_subpixel_geometry(&modifier, points[i], points[i + 1], 1, 1, buf);
1785 // take green channel distortion, like distort_mask() does, so x and y come from the
1786 // same color channel's distortion field instead of mixing red's x with green's y.
1787 points[i] = buf[2];
1788 points[i + 1] = buf[3];
1789 }
1790 }
1791
1792
1793 return 1;
1794}
1795
1797 float *const __restrict points, size_t points_count)
1798{
1800
1801 if(!_lens_data_available(d)) return 0;
1802
1803 const int used_lf_mask = _lens_mask_for_mono(dt_image_is_monochrome(&self->dev->image_storage));
1804
1805 const float orig_w = piece->buf_in.width, orig_h = piece->buf_in.height;
1806 int modflags;
1807 ls_modifier_t modifier;
1808 get_modifier(&modflags, orig_w, orig_h, d, used_lf_mask, FALSE, &modifier, NULL);
1809
1810
1812 {
1813 __OMP_PARALLEL_FOR__(firstprivate(points_count, modifier, points) if(points_count > 100))
1814 for(size_t i = 0; i < points_count * 2; i += 2)
1815 {
1816 float DT_ALIGNED_ARRAY buf[6];
1817 ls_modifier_apply_subpixel_geometry(&modifier, points[i], points[i + 1], 1, 1, buf);
1818 // take green channel distortion, like distort_mask() does, so x and y come from the
1819 // same color channel's distortion field instead of mixing red's x with green's y.
1820 points[i] = buf[2];
1821 points[i + 1] = buf[3];
1822 }
1823 }
1824
1825
1826 return 1;
1827}
1828
1829// TODO: Shall we keep DT_LENS_MODIFY_TCA in the modifiers?
1831 const float *const in, float *const out, const dt_iop_roi_t *const roi_in,
1832 const dt_iop_roi_t *const roi_out)
1833{
1834 (void)pipe;
1835 const dt_iop_lensfun_data_t *const d = (dt_iop_lensfun_data_t *)piece->data;
1836
1838 {
1839 dt_iop_image_copy_by_size(out, in, roi_out->width, roi_out->height, 1);
1840 return;
1841 }
1842
1843 const float orig_w = roi_in->scale * piece->buf_in.width, orig_h = roi_in->scale * piece->buf_in.height;
1844 int modflags;
1845 ls_modifier_t modifier;
1847 /*DT_LENS_MODIFY_TCA |*/ DT_LENS_MODIFY_DISTORTION | DT_LENS_MODIFY_GEOMETRY
1849 FALSE, &modifier, NULL);
1850
1852 {
1853 dt_iop_image_copy_by_size(out, in, roi_out->width, roi_out->height, 1);
1854 return;
1855 }
1856
1857 const struct dt_interpolation *const interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF_WARP);
1858
1859 // acquire temp memory for distorted pixel coords
1860 const size_t bufsize = (size_t)roi_out->width * 2 * 3;
1861 size_t padded_bufsize;
1863 if(IS_NULL_PTR(buf)) return;
1864 __OMP_PARALLEL_FOR__(firstprivate(buf, padded_bufsize, d, modifier, in, out, interpolation, roi_in, roi_out))
1865 for(int y = 0; y < roi_out->height; y++)
1866 {
1867 float *bufptr = (float*)dt_get_perthread(buf, padded_bufsize);
1868 ls_modifier_apply_subpixel_geometry(&modifier, roi_out->x, roi_out->y + y, roi_out->width, 1, bufptr);
1869
1870 // reverse transform the global coords from lf to our buffer
1871 float *_out = out + (size_t)y * roi_out->width;
1872 for(int x = 0; x < roi_out->width; x++, bufptr += 6, _out++)
1873 {
1874 if(d->do_nan_checks && (!isfinite(bufptr[2]) || !isfinite(bufptr[3])))
1875 {
1876 *_out = 0.0f;
1877 continue;
1878 }
1879
1880 // take green channel distortion also for alpha channel
1881 const float pi0 = bufptr[2] - roi_in->x;
1882 const float pi1 = bufptr[3] - roi_in->y;
1883 *_out = dt_interpolation_compute_sample(interpolation, in, pi0, pi1, roi_in->width, roi_in->height, 1,
1884 roi_in->width);
1885 }
1886 }
1887
1888
1890}
1891
1893 struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out,
1894 const dt_iop_roi_t *roi_in)
1895{
1896 *roi_out = *roi_in;
1897}
1898
1899void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1901 const dt_iop_roi_t *const roi_out, dt_iop_roi_t *roi_in)
1902{
1904 *roi_in = *roi_out;
1905 // inverse transform with given params
1906
1907 if(!_lens_data_available(d)) return;
1908
1909 const float orig_w = roi_in->scale * piece->buf_in.width;
1910 const float orig_h = roi_in->scale * piece->buf_in.height;
1911 int modflags;
1912 ls_modifier_t modifier;
1914
1916 {
1917 const int xoff = roi_in->x;
1918 const int yoff = roi_in->y;
1919 const int width = roi_in->width;
1920 const int height = roi_in->height;
1921 const int awidth = abs(width);
1922 const int aheight = abs(height);
1923 const int xstep = (width < 0) ? -1 : 1;
1924 const int ystep = (height < 0) ? -1 : 1;
1925
1926 float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX;
1927 const size_t nbpoints = 2 * awidth + 2 * aheight;
1928
1929 // ROI planning passes the active pipe now, but this temporary edge buffer only needs an
1930 // allocator bucket id, so use a stable generic bucket.
1931 float *const buf = (float *)dt_pixelpipe_cache_alloc_align_cache(sizeof(float) * nbpoints * 2 * 3,
1933 if(IS_NULL_PTR(buf)) return;
1934
1935#ifdef _OPENMP
1936#pragma omp parallel default(none) reduction(min : xm, ym) reduction(max : xM, yM) \
1937 firstprivate(modifier, xoff, yoff, awidth, aheight, width, height, nbpoints, ystep, xstep, buf)
1938#endif
1939 {
1940 __OMP_FOR__()
1941 for(int i = 0; i < awidth; i++)
1942 ls_modifier_apply_subpixel_geometry(&modifier, xoff + i * xstep, yoff, 1, 1, buf + 6 * i);
1943 __OMP_FOR__()
1944 for(int i = 0; i < awidth; i++)
1945 ls_modifier_apply_subpixel_geometry(&modifier, xoff + i * xstep, yoff + (height - 1), 1, 1, buf + 6 * (awidth + i));
1946 __OMP_FOR__()
1947 for(int j = 0; j < aheight; j++)
1948 ls_modifier_apply_subpixel_geometry(&modifier, xoff, yoff + j * ystep, 1, 1, buf + 6 * (2 * awidth + j));
1949 __OMP_FOR__()
1950 for(int j = 0; j < aheight; j++)
1951 ls_modifier_apply_subpixel_geometry(&modifier, xoff + (width - 1), yoff + j * ystep, 1, 1, buf + 6 * (2 * awidth + aheight + j));
1952
1953#ifdef _OPENMP
1954#pragma omp barrier
1955#endif
1956 __OMP_FOR__()
1957 for(size_t k = 0; k < nbpoints; k++)
1958 {
1959 // iterate over RGB channels x and y coordinates
1960 for(size_t c = 0; c < 6; c+=2)
1961 {
1962 const float x = buf[6 * k + c];
1963 const float y = buf[6 * k + c + 1];
1964 xm = isnan(x) ? xm : MIN(xm, x);
1965 xM = isnan(x) ? xM : MAX(xM, x);
1966 ym = isnan(y) ? ym : MIN(ym, y);
1967 yM = isnan(y) ? yM : MAX(yM, y);
1968 }
1969 }
1970 }
1971
1973
1974 // LensFun can return NAN coords, so we need to handle them carefully.
1975 if(!isfinite(xm) || !(0 <= xm && xm < orig_w)) xm = 0;
1976 if(!isfinite(xM) || !(1 <= xM && xM < orig_w)) xM = orig_w;
1977 if(!isfinite(ym) || !(0 <= ym && ym < orig_h)) ym = 0;
1978 if(!isfinite(yM) || !(1 <= yM && yM < orig_h)) yM = orig_h;
1979
1981 roi_in->x = fmaxf(0.0f, roundf(xm - interpolation->width));
1982 roi_in->y = fmaxf(0.0f, roundf(ym - interpolation->width));
1983 roi_in->width = roundf(fminf(orig_w - roi_in->x, xM - roi_in->x + interpolation->width));
1984 roi_in->height = roundf(fminf(orig_h - roi_in->y, yM - roi_in->y + interpolation->width));
1985
1986 // sanity check.
1987 roi_in->x = CLAMP(roi_in->x, 0, (int)floorf(orig_w));
1988 roi_in->y = CLAMP(roi_in->y, 0, (int)floorf(orig_h));
1989 roi_in->width = CLAMP(roi_in->width, 1, (int)ceilf(orig_w) - roi_in->x);
1990 roi_in->height = CLAMP(roi_in->height, 1, (int)ceilf(orig_h) - roi_in->y);
1991 }
1992}
1993
1994/* --- the shared geometry core ----------------------------------------------------------
1995 *
1996 * lens resolves its effective parameters and then builds a lensfun state out of them, and both
1997 * halves are needed twice: once for the pixel pipe, once for the record the geometry service
1998 * composes GUI coordinates from (develop/geometry/geometry.h). Expressed once here.
1999 *
2000 * Note what lens does NOT contribute: modify_roi_out() is the identity, so this module changes
2001 * no dimensions. It is on the geometry roster purely for its point transforms.
2002 */
2003
2025 const dt_iop_lensfun_params_t *const p)
2026{
2027 return (p->modified == 0) ? (const dt_iop_lensfun_params_t *)self->default_params : p;
2028}
2029
2039{
2040 (void)self;
2041 memset(&d->ls_lens, 0, sizeof(d->ls_lens));
2042 d->ls_have = FALSE;
2043
2044 /* No lock. The reader is lock-free by construction and its handle is thread-local, so a
2045 * pipeline thread resolving a lens no longer serialises against anything -- least of all
2046 * against RawSpeed decoding a file, which is what sharing dt_plugin_threadsafe_mutex()
2047 * used to mean. And nothing is owned on return: an ls_lens_t is a value, valid after the
2048 * handle that produced it is closed, so there is no deep copy to make and no delete to
2049 * forget. */
2050 long long mount_id = 0;
2051 float camera_crop = 0.f;
2052
2053 /* The image's own crop factor, which reload_defaults() takes from EXIF and the camera
2054 * picker overwrites. Seeded unconditionally because piece->data is REUSED across commits:
2055 * assigning it only inside the lookup below left a piece whose previous params resolved a
2056 * camera still carrying that camera's crop when the current ones do not resolve one. */
2057 d->crop = p->crop;
2058
2059 if(p->camera[0])
2060 {
2061 ls_camera_t camera;
2062 /* The stored camera name is a model with no maker -- what the picker writes and what
2063 * EXIF gives -- so the matcher is asked for one rather than guessing the other. */
2064 if(_ls_find_camera(NULL, p->camera, &camera))
2065 {
2066 d->crop = camera.crop_factor;
2067 camera_crop = camera.crop_factor;
2068 mount_id = camera.mount_id;
2069 }
2070 }
2071
2072 /* No camera, no database lens -- and that is a correctness rule, not caution.
2073 *
2074 * The mount is what makes a lens name mean one lens. Without it the search runs over the
2075 * whole catalogue, where hundreds of unrelated optics share the names "fixed lens" and
2076 * "festes objektiv", tie on score, and are separated by nothing at all. Correcting from
2077 * an arbitrary pick among those is how a Ricoh GR II came to be corrected with a 5.9 mm
2078 * compact's distortion.
2079 *
2080 * It also restores the panel's own invariant. gui_update() shows a lens only when a
2081 * camera resolved, so this was the one path where the pipeline corrected from something
2082 * the panel could not name and the user could not check or override. The recovery is the
2083 * picker: choose the body by hand, the mount is known, and the correct lens resolves and
2084 * is shown. */
2085 if(p->lens[0] && mount_id > 0)
2086 {
2087 const long long lens_id = _ls_find_lens(mount_id, camera_crop, p->focal, p->lens);
2088 ls_db_t *db = _ls_db();
2089 if(lens_id >= 0 && !IS_NULL_PTR(db) && ls_db_lens_by_id(db, lens_id, &d->ls_lens) == 1)
2090 {
2091 d->ls_have = TRUE;
2092 }
2093 }
2094 else if(p->lens[0])
2095 {
2096 /* DT_DEBUG_PIPE, not ALWAYS: nobody chose this, so it is a default declining to guess
2097 * rather than a request that could not be honoured -- and this runs from the GUI's
2098 * availability query too, not only at commit. The panel already says it, by showing
2099 * neither a camera nor a lens. */
2101 "[lens] `%s' is not a camera this database knows, so `%s' cannot be resolved to"
2102 " one lens; correcting from the database is declined\n", p->camera, p->lens);
2103 }
2104
2105 /* Typed coefficients are a SOURCE of their own, not an edit applied to a database row.
2106 *
2107 * They used to be written inside the lookup above, over the calibration of a lens the
2108 * database had just returned -- so on a body-and-lens pair the database does not know,
2109 * d->ls_have stayed FALSE, _lens_data_available() answered no, and process(),
2110 * process_cl(), the three distort_*() callbacks and modify_roi_in() all copied their
2111 * input and returned. The two sliders moved and the pipeline never saw them, on exactly
2112 * the images manual correction exists for.
2113 *
2114 * With a database lens the manual entry still REPLACES its aberration, which is what
2115 * manual means, and the coefficients live in that lens's calibration frame. With none,
2116 * the frame is a lens declared calibrated on THIS camera, so ls_modifier_init()'s
2117 * calibration-crop / image-crop rescaling is 1 and the two numbers act directly.
2118 * aspect_ratio is deliberately left at 0, which the library reads as its own 1.5 default
2119 * -- the same normalisation a 3:2-calibrated database entry gives, so a coefficient does
2120 * not change meaning on the day a profile for the lens appears.
2121 *
2122 * Writing it here rather than there also means it no longer depends on p->lens[0] being
2123 * non-empty: an unnamed lens is not a reason to refuse numbers the user typed. */
2125 {
2126 if(!d->ls_have)
2127 {
2128 d->ls_lens.type = LS_LENS_RECTILINEAR;
2129 d->ls_lens.crop_factor = d->crop;
2130 d->ls_lens.min_focal = p->focal;
2131 d->ls_lens.max_focal = p->focal;
2132 d->ls_have = TRUE;
2133 }
2134
2135 /* One entry at the shooting focal is exactly what the two sliders describe. ls_lens_t
2136 * is this module's own copy, so overwriting the array is both cheaper and clearer than
2137 * upstream's remove-every-entry-then-add dance on a shared object -- which is what the
2138 * code here used to do, twice, under two different lensfun APIs. */
2139 d->ls_lens.n_tca = 1;
2140 d->ls_lens.tca[0].model = LS_TCA_LINEAR;
2141 d->ls_lens.tca[0].focal = p->focal;
2142 d->ls_lens.tca[0].terms[0] = p->tca_r;
2143 d->ls_lens.tca[0].terms[1] = p->tca_b;
2144 for(int i = 2; i < 6; i++) d->ls_lens.tca[0].terms[i] = 0.f;
2145 }
2146
2147 d->modify_flags = p->modify_flags;
2148 if(dt_image_is_monochrome(&self->dev->image_storage)) d->modify_flags &= ~DT_LENS_MODIFY_TCA;
2149 d->inverse = p->inverse;
2150 d->scale = p->scale;
2151 d->focal = p->focal;
2152 d->aperture = p->aperture;
2153 d->distance = p->distance;
2154 d->target_geom = p->target_geom;
2155 d->do_nan_checks = TRUE;
2156 d->tca_override = p->tca_override;
2157
2158 /* The maker's own profile, if any axis asked for it and the file carries one.
2159 *
2160 * Resolved HERE, at commit, for the same reason the database lens is: the pixel path gets
2161 * values and does no lookups. ls_vendor_resolve() normalises whichever vendor format the
2162 * file holds -- Sony, Fuji, Olympus or a DNG opcode list -- straight into the knot table
2163 * the evaluators consume; past that call nothing here knows which maker wrote it.
2164 *
2165 * The finetune is NULL: "as the maker measured", which is the library's documented
2166 * meaning for it. The per-class strength blends the vendor GUIs offer are not exposed by
2167 * this module. */
2168 d->knots_have = FALSE;
2169 d->knots_scale = 1.f;
2170 {
2171 gboolean wants_embedded = FALSE;
2174
2175 if(wants_embedded)
2176 {
2177 const dt_image_t *const img = &self->dev->image_storage;
2178 float scale = 1.f;
2179 const int got = ls_vendor_resolve(&img->exif_correction, NULL,
2180 img->p_width, img->p_height, &d->ls_knots, &scale);
2181
2182 /* The two failure reports stay distinct, because they mean different things to the
2183 * person reading them: "this camera embeds nothing" is a fact about the hardware,
2184 * "we failed to read what it embedded" is a bug to report. Both then correct from
2185 * the database, and both say so -- a user who picked a source and got another one
2186 * is entitled to know. Once, at commit; not per pipe per frame. */
2187 if(got == 0)
2189 "[lens] an axis asks for the vendor profile but this file carries none;"
2190 " correcting from the community profile instead\n");
2191 else if(got < 0)
2193 "[lens] this file's vendor profile could not be decoded;"
2194 " correcting from the community profile instead\n");
2195 else
2196 {
2197 d->knots_scale = (scale > 0.f) ? scale : 1.f;
2198 d->knots_have = TRUE;
2199 }
2200 }
2201 }
2202
2203 /*
2204 * there are certain situations when LensFun can return NAN coordinated.
2205 * most common case would be when the FOV is increased.
2206 */
2207 if(d->target_geom == DT_LENS_RECTILINEAR)
2208 {
2209 d->do_nan_checks = FALSE;
2210 }
2211 else if((int)d->target_geom == (int)d->ls_lens.type)
2212 {
2213 d->do_nan_checks = FALSE;
2214 }
2215}
2216
2222
2225{
2227
2228 // FIXME: this is utter shit and should be made into a GUI "mode".
2229 // If p->modified == 0, mode = auto and hide all controls
2230 // if p->modidified == 1, mode = manual and show all controls.
2231 if(((dt_iop_lensfun_params_t *)p1)->modified == 0)
2232 {
2233 // Temporary fix pending GUI unfucking
2234 dt_iop_compute_module_hash(self, self->dev->forms);
2235 }
2236
2238
2239 piece->cache_output_on_ram = TRUE;
2240}
2241
2242/* --- the geometry service's view of this module (develop/geometry/geometry.h) ---------
2243 *
2244 * The one record in the service whose payload is not plain data: evaluating a lens correction
2245 * needs the resolved calibration, so the record owns a
2246 * deep copy and frees it. That is what dt_geometry_record_t::free_data exists for.
2247 */
2248
2254
2255static void _lens_free_data(void *ptr)
2256{
2258 if(!g) return;
2259 free(g);
2260}
2261
2264static int _lens_geometry_apply(const void *data, const dt_geometry_record_t *const record,
2265 float *points, size_t points_count, gboolean inverse)
2266{
2267 const dt_iop_lens_geometry_t *const g = (const dt_iop_lens_geometry_t *)data;
2268 const dt_iop_lensfun_data_t *const d = &g->data;
2269
2270 if(!_lens_data_available(d)) return 0;
2271 if(record->in.width <= 0 || record->in.height <= 0) return 0;
2272
2273 int modflags = 0;
2274 ls_modifier_t modifier;
2275 if(!get_modifier(&modflags, record->in.width, record->in.height, d, g->used_lf_mask, inverse,
2276 &modifier, NULL))
2277 return 0;
2278
2280 {
2281 for(size_t i = 0; i < points_count * 2; i += 2)
2282 {
2283 float DT_ALIGNED_ARRAY buf[6];
2284 ls_modifier_apply_subpixel_geometry(&modifier, points[i], points[i + 1], 1, 1, buf);
2285 // green channel, like distort_transform() and distort_mask() do, so x and y come from the
2286 // same colour channel's distortion field instead of mixing red's x with green's y.
2287 points[i] = buf[2];
2288 points[i + 1] = buf[3];
2289 }
2290 }
2291
2292 return 1;
2293}
2294
2295static int _lens_geometry_transform(const void *data, const dt_geometry_record_t *const record,
2296 dt_geometry_chain_t *chain, float *points, size_t points_count)
2297{
2298 return _lens_geometry_apply(data, record, points, points_count, TRUE);
2299}
2300
2301static int _lens_geometry_backtransform(const void *data, const dt_geometry_record_t *const record,
2302 dt_geometry_chain_t *chain, float *points, size_t points_count)
2303{
2304 return _lens_geometry_apply(data, record, points, points_count, FALSE);
2305}
2306
2308 /* .map_size = */ NULL, // modify_roi_out() is the identity: lens changes no dimensions
2309 /* .transform = */ _lens_geometry_transform,
2310 /* .backtransform = */ _lens_geometry_backtransform,
2311};
2312
2314{
2316 if(!g) return FALSE;
2317
2320 _lens_build_data(self, p, &g->data);
2321 g->used_lf_mask = _lens_used_mask(self);
2322
2323 record->data = g;
2324 record->free_data = _lens_free_data;
2325 record->vtable = &_lens_geometry_vtable;
2326 return TRUE;
2327}
2328
2334
2336{
2337 /* init_pipe() may have failed to allocate, and cleanup runs regardless. */
2338 if(IS_NULL_PTR(piece->data)) return;
2339
2340 /* Nothing to free but the piece itself: ls_lens_t is a value living inside it, where the
2341 * lfLens it replaces was a heap object this had to remember to delete. */
2342 dt_free_align(piece->data);
2343 piece->data = NULL;
2344}
2345
2347{
2348 const int program = 2; // basic.cl, from programs.conf
2351 module->data = gd;
2352 gd->kernel_lens_distort_bilinear = dt_opencl_create_kernel(program, "lens_distort_bilinear");
2353 gd->kernel_lens_distort_bicubic = dt_opencl_create_kernel(program, "lens_distort_bicubic");
2354 gd->kernel_lens_distort_mitchell = dt_opencl_create_kernel(program, "lens_distort_mitchell");
2355 gd->kernel_lens_vignette = dt_opencl_create_kernel(program, "lens_vignette");
2356
2357 /* Nothing to pre-warm any more. Opening the calibration database is one mmap of an
2358 * already-parsed file, done lazily per thread on first use and measured at 0.18 ms --
2359 * there is no 100 ms XML parse left to hide behind a startup thread. */
2360}
2361
2363
2365{
2366 char *new_lens;
2367 const dt_image_t *img = &module->dev->image_storage;
2368
2369 // reload image specific stuff
2370 // get all we can from exif:
2372
2374 g_strlcpy(d->lens, new_lens, sizeof(d->lens));
2376 g_strlcpy(d->camera, img->exif_model, sizeof(d->camera));
2377 d->crop = img->exif_crop;
2378 d->aperture = img->exif_aperture;
2379 d->focal = img->exif_focal_length;
2380 d->scale = 1.0;
2383
2384 /* Everything decided here is now WRITTEN DOWN, rather than recomputed whenever the image
2385 * is opened. See _lens_effective_params() for what the alternative cost. */
2386 d->modified = 1;
2387
2388 /* Prefer what the camera measured about its own lens, per axis, whenever the file carries
2389 * it. The maker had the actual body and the actual lens on a bench; the database has a
2390 * community measurement of that model. Where both exist the maker's is the better default,
2391 * and where only one exists this picks the one that works.
2392 *
2393 * Per axis, because the makers do not all write the same set: an Olympus body publishes
2394 * distortion and lateral CA and no falloff, so that axis correctly keeps the database.
2395 *
2396 * Scale stays 1: the embedded resolver applies the profile's own autoscale, which already
2397 * clears the borders it leaves. Anything else here would be a second, arbitrary zoom on
2398 * top of a factor the maker chose. */
2400 {
2404 }
2405 // if we did not find focus_distance in EXIF, lets default to 1000
2406 d->distance = img->exif_focus_distance == 0.0f ? 1000.0f : img->exif_focus_distance;
2407 d->target_geom = DT_LENS_RECTILINEAR;
2408
2409 if(dt_image_is_monochrome(img))
2410 d->modify_flags &= ~DT_LENS_MODIFY_TCA;
2411
2412 // init crop from db:
2413 char model[100]; // truncate often complex descriptions.
2414 g_strlcpy(model, img->exif_model, sizeof(model));
2415 for(char cnt = 0, *c = model; c < model + 100 && *c != '\0'; c++)
2416 if(*c == ' ')
2417 if(++cnt == 2) *c = '\0';
2418 if(img->exif_maker[0] || model[0])
2419 {
2420 ls_camera_t cam;
2421 if(!_ls_find_camera(img->exif_maker, img->exif_model, &cam)) return;
2422
2423 /* Upstream spells a real fact into the mount NAME: a lower-case initial means a
2424 * fixed-lens camera. That is how a compact is told from an interchangeable-lens body,
2425 * and it decides both branches below. */
2426 char mount[128] = { 0 };
2427 ls_db_t *db = _ls_db();
2428 if(IS_NULL_PTR(db)) return;
2429 ls_db_mount_name(db, cam.mount_id, mount, sizeof(mount));
2430 const gboolean fixed_lens = (mount[0] != '\0') && islower((unsigned char)mount[0]);
2431
2432 long long lens_id = _ls_find_lens(cam.mount_id, cam.crop_factor, d->focal, d->lens);
2433
2434 if(lens_id < 0 && fixed_lens)
2435 {
2436 /* A fixed-lens camera whose EXIF lens string matched nothing -- it is "(65535)", or
2437 * a name upstream files as "fixed lens". The lens is whatever is built into this
2438 * mount, so ask the mount directly instead of matching a name. */
2439 g_strlcpy(d->lens, "", sizeof(d->lens));
2440
2441 const int n = ls_db_lenses_for_mount(db, cam.mount_id, NULL, 0);
2442 if(n > 0)
2443 {
2444 long long *ids = (long long *)dt_alloc_align(sizeof(long long) * (size_t)n);
2445 if(!IS_NULL_PTR(ids))
2446 {
2447 ls_db_lenses_for_mount(db, cam.mount_id, ids, n);
2448 /* The shortest model name, as before: a fixed-lens mount can carry several
2449 * entries for one physical lens and the shortest is the plain one. */
2450 size_t shortest = SIZE_MAX;
2451 for(int i = 0; i < n; i++)
2452 {
2453 char maker[128] = "", lmodel[256] = "";
2454 if(ls_db_lens_name(db, ids[i], maker, sizeof(maker), lmodel, sizeof(lmodel)) <= 0)
2455 continue;
2456 const size_t len = strlen(lmodel);
2457 if(len < shortest)
2458 {
2459 shortest = len;
2460 lens_id = ids[i];
2461 g_strlcpy(d->lens, lmodel, sizeof(d->lens));
2462 }
2463 }
2464 dt_free_align(ids);
2465 }
2466 }
2467 }
2468
2469 if(lens_id >= 0)
2470 {
2471 ls_lens_t lens;
2472 if(ls_db_lens_by_id(db, lens_id, &lens) == 1)
2473 d->target_geom = (dt_lens_type_t)lens.type;
2474 }
2475
2476 d->crop = cam.crop_factor;
2477 d->scale = get_autoscale(module, d);
2478 module->workflow_enabled = dt_image_needs_rawprepare(img);
2479 }
2480
2481 // reload_defaults() stays params-only and never touches gui_data.
2482}
2483
2485{
2487
2488 /* Each thread's handle closes when that thread ends, except the one of the thread unloading
2489 * the modules: the main thread ends in exit(), which runs no thread-local destructor. */
2491
2492 dt_opencl_free_kernel(gd->kernel_lens_distort_bilinear);
2493 dt_opencl_free_kernel(gd->kernel_lens_distort_bicubic);
2494 dt_opencl_free_kernel(gd->kernel_lens_distort_mitchell);
2495 dt_opencl_free_kernel(gd->kernel_lens_vignette);
2496 dt_free(module->data);
2497}
2498
2501
2502/* simple function to compute the floating-point precision
2503 which is enough for "normal use". The criteria is to have
2504 about 3 leading digits after the initial zeros. */
2505static int precision(double x, double adj)
2506{
2507 x *= adj;
2508
2509 if(x == 0) return 1;
2510 if(x < 1.0)
2511 if(x < 0.1)
2512 if(x < 0.01)
2513 return 5;
2514 else
2515 return 4;
2516 else
2517 return 3;
2518 else if(x < 100.0)
2519 if(x < 10.0)
2520 return 2;
2521 else
2522 return 1;
2523 else
2524 return 0;
2525}
2526
2527/* -- ufraw ptr array functions -- */
2528
2529static int ptr_array_insert_sorted(GPtrArray *array, const void *item, GCompareFunc compare)
2530{
2531 int length = array->len;
2532 g_ptr_array_set_size(array, length + 1);
2533 const void **root = (const void **)array->pdata;
2534
2535 int m = 0, l = 0, r = length - 1;
2536
2537 // Skip trailing NULL, if any
2538 if(l <= r && !root[r]) r--;
2539
2540 while(l <= r)
2541 {
2542 m = (l + r) / 2;
2543 int cmp = compare(root[m], item);
2544
2545 if(cmp == 0)
2546 {
2547 ++m;
2548 goto done;
2549 }
2550 else if(cmp < 0)
2551 l = m + 1;
2552 else
2553 r = m - 1;
2554 }
2555 if(r == m) m++;
2556
2557done:
2558 memmove(root + m + 1, root + m, sizeof(void *) * (length - m));
2559 root[m] = item;
2560 return m;
2561}
2562
2563static int ptr_array_find_sorted(const GPtrArray *array, const void *item, GCompareFunc compare)
2564{
2565 int length = array->len;
2566 void **root = array->pdata;
2567
2568 int l = 0, r = length - 1;
2569 int m = 0, cmp = 0;
2570
2571 if(!length) return -1;
2572
2573 // Skip trailing NULL, if any
2574 if(!root[r]) r--;
2575
2576 while(l <= r)
2577 {
2578 m = (l + r) / 2;
2579 cmp = compare(root[m], item);
2580
2581 if(cmp == 0)
2582 return m;
2583 else if(cmp < 0)
2584 l = m + 1;
2585 else
2586 r = m - 1;
2587 }
2588
2589 return -1;
2590}
2591
2592static void ptr_array_insert_index(GPtrArray *array, const void *item, int index)
2593{
2594 const void **root;
2595 int length = array->len;
2596 g_ptr_array_set_size(array, length + 1);
2597 root = (const void **)array->pdata;
2598 memmove(root + index + 1, root + index, sizeof(void *) * (length - index));
2599 root[index] = item;
2600}
2601
2602/* -- end ufraw ptr array functions -- */
2603
2604/* -- camera -- */
2605
2616static void _lens_params_set_camera(dt_iop_module_t *self, const long long camera_id)
2617{
2619
2620 ls_db_t *db = _ls_db();
2621 char maker[128] = "", model[256] = "", variant[128] = "";
2622 ls_camera_t cam;
2623 if(camera_id < 0 || IS_NULL_PTR(db)
2624 || ls_db_camera_name(db, camera_id, maker, sizeof(maker), model, sizeof(model),
2625 variant, sizeof(variant)) != 1
2626 || ls_db_camera_by_id(db, camera_id, &cam) != 1)
2627 return;
2628
2629 g_strlcpy(p->camera, model, sizeof(p->camera));
2630 p->crop = cam.crop_factor;
2631}
2632
2641static void camera_set(dt_iop_module_t *self, long long camera_id)
2642{
2644
2645 ls_db_t *db = _ls_db();
2646 char maker[128] = "", model[256] = "", variant[128] = "";
2647 ls_camera_t cam;
2648 if(camera_id < 0 || IS_NULL_PTR(db)
2649 || ls_db_camera_name(db, camera_id, maker, sizeof(maker), model, sizeof(model),
2650 variant, sizeof(variant)) != 1
2651 || ls_db_camera_by_id(db, camera_id, &cam) != 1)
2652 {
2654 gtk_widget_set_tooltip_text(GTK_WIDGET(g->camera_model), "");
2655 g->camera_id = -1;
2656 return;
2657 }
2658
2659 g->camera_id = camera_id;
2660
2661 gchar *fm = maker[0] ? g_strdup_printf("%s, %s", maker, model) : g_strdup(model);
2663 dt_free(fm);
2664
2665 // sizeof(variant) + 4, not 128: the format adds " (" and ")" around a string that can
2666 // itself fill variant[], so an equal-sized buffer drops the closing parenthesis on a long
2667 // camera variant. Derived from variant's size so it stays right if that changes.
2668 char _variant[sizeof(variant) + 4];
2669 if(variant[0])
2670 snprintf(_variant, sizeof(_variant), " (%s)", variant);
2671 else
2672 _variant[0] = 0;
2673
2674 char mount[128] = "";
2675 ls_db_mount_name(db, cam.mount_id, mount, sizeof(mount));
2676
2677 fm = g_strdup_printf(_("maker:\t\t%s\n"
2678 "model:\t\t%s%s\n"
2679 "mount:\t\t%s\n"
2680 "crop factor:\t%.1f"),
2681 maker, model, _variant, mount, cam.crop_factor);
2682 gtk_widget_set_tooltip_text(GTK_WIDGET(g->camera_model), fm);
2683 dt_free(fm);
2684}
2685
2686static void camera_menu_select(GtkMenuItem *menuitem, gpointer user_data)
2687{
2688 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2689
2690 /* First, and for the whole handler: a suppressed callback is a programmatic widget
2691 * update, and this one writes parameters and commits history. */
2692 if(dt_gui_widgets_suppressed()) return;
2693
2694 const long long camera_id =
2695 (long long)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), "lens-camera-id"));
2696
2698 _lens_params_set_camera(self, camera_id);
2699 p->modified = 1;
2700
2701 /* View second, because it reads the parameters just written. The camera decides the mount
2702 * and the crop factor, and a lens is matched against those -- so a lens that matched the
2703 * old camera may not match the new one, and the other way round. Every other caller of
2704 * camera_set() runs a lens_set() straight afterwards and gets the rebuild from there;
2705 * this one does not, so it asks itself. */
2706 {
2708 camera_set(self, camera_id);
2711 }
2712
2713 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
2714}
2715
2721static void camera_menu_fill(dt_iop_module_t *self, const long long *ids, int n)
2722{
2725
2726 if(g->camera_menu)
2727 {
2728 gtk_widget_destroy(GTK_WIDGET(g->camera_menu));
2729 g->camera_menu = NULL;
2730 }
2731
2732 ls_db_t *db = _ls_db();
2733 if(IS_NULL_PTR(db)) return;
2734
2735 /* Count all existing camera makers and create a sorted list */
2738 for(int i = 0; i < n; i++)
2739 {
2740 char maker[128] = "", model[256] = "", variant[128] = "";
2741 if(ls_db_camera_name(db, ids[i], maker, sizeof(maker), model, sizeof(model),
2742 variant, sizeof(variant)) != 1)
2743 continue;
2744
2745 GtkWidget *submenu, *item;
2747 if(idx < 0)
2748 {
2749 /* No such maker yet, insert it into the array. The strings are OWNED now: they used
2750 * to point into a database that outlived the menu, and they no longer do. */
2752 /* Create a submenu for cameras by this maker */
2755 }
2756
2758 /* Append current camera name to the submenu */
2759 if(!variant[0])
2761 else
2762 {
2763 gchar *fm = g_strdup_printf("%s (%s)", model, variant);
2765 dt_free(fm);
2766 }
2767 gtk_widget_show(item);
2768 g_object_set_data(G_OBJECT(item), "lens-camera-id", GINT_TO_POINTER((gint)ids[i]));
2769 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(camera_menu_select), self);
2771 }
2772
2773 g->camera_menu = GTK_MENU(gtk_menu_new());
2774 for(unsigned i = 0; i < makers->len; i++)
2775 {
2777 gtk_widget_show(item);
2778 gtk_menu_shell_append(GTK_MENU_SHELL(g->camera_menu), item);
2780 }
2781
2784}
2785
2787static long long *_camera_all_ids(int *out_n)
2788{
2789 *out_n = 0;
2790 ls_db_t *db = _ls_db();
2791 if(IS_NULL_PTR(db)) return NULL;
2792 const int n = ls_db_list_cameras(db, NULL, 0);
2793 if(n <= 0) return NULL;
2794 long long *ids = (long long *)dt_alloc_align(sizeof(long long) * (size_t)n);
2795 if(IS_NULL_PTR(ids)) return NULL;
2796 *out_n = ls_db_list_cameras(db, ids, n);
2797 return ids;
2798}
2799
2800static void parse_model(const char *txt, char *model, size_t sz_model)
2801{
2802 while(txt[0] && isspace(txt[0])) txt++;
2803 size_t len = strlen(txt);
2804 if(len > sz_model - 1) len = sz_model - 1;
2805 memcpy(model, txt, len);
2806 model[len] = 0;
2807}
2808
2809static void camera_menusearch_clicked(GtkWidget *button, gpointer user_data)
2810{
2811 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
2813
2814 (void)button;
2815
2816 int n = 0;
2817 long long *ids = _camera_all_ids(&n);
2818 if(IS_NULL_PTR(ids)) return;
2819 camera_menu_fill(self, ids, n);
2820 dt_free_align(ids);
2821
2823}
2824
2825
2826/* -- end camera -- */
2827
2829{
2831 const char *text = dt_bauhaus_combobox_get_text(widget);
2832 if(text) (void)sscanf(text, "%f", &p->focal);
2833 p->modified = 1;
2834 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
2835}
2836
2838{
2840 const char *text = dt_bauhaus_combobox_get_text(widget);
2841 if(text) (void)sscanf(text, "%f", &p->aperture);
2842 p->modified = 1;
2843 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
2844}
2845
2847{
2849 const char *text = dt_bauhaus_combobox_get_text(widget);
2850 if(text) (void)sscanf(text, "%f", &p->distance);
2851 p->modified = 1;
2852 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
2853}
2854
2855static void delete_children(GtkWidget *widget, gpointer data)
2856{
2857 (void)data;
2858 gtk_widget_destroy(widget);
2859}
2860
2862static const char *_lens_type_name(int type)
2863{
2864 switch(type)
2865 {
2866 case DT_LENS_RECTILINEAR: return _("rectilinear");
2867 case DT_LENS_FISHEYE: return _("fisheye");
2868 case DT_LENS_PANORAMIC: return _("panoramic");
2869 case DT_LENS_EQUIRECTANGULAR: return _("equirectangular");
2870 case DT_LENS_FISHEYE_ORTHOGRAPHIC: return _("orthographic fisheye");
2871 case DT_LENS_FISHEYE_STEREOGRAPHIC: return _("stereographic fisheye");
2872 case DT_LENS_FISHEYE_EQUISOLID: return _("equisolid fisheye");
2873 case DT_LENS_FISHEYE_THOBY: return _("Thoby fisheye");
2874 default: return _("unknown");
2875 }
2876}
2877
2885static void _lens_params_set_lens(dt_iop_module_t *self, const long long lens_id)
2886{
2888
2889 ls_db_t *db = _ls_db();
2890 char l_maker[128] = "", l_model[256] = "";
2891 if(lens_id < 0 || IS_NULL_PTR(db)
2892 || ls_db_lens_name(db, lens_id, l_maker, sizeof(l_maker), l_model, sizeof(l_model)) <= 0)
2893 return;
2894
2895 g_strlcpy(p->lens, l_model, sizeof(p->lens));
2896}
2897
2900static void lens_set(dt_iop_module_t *self, long long lens_id)
2901{
2903 /* const, and effective: this reads the focal length, aperture and distance to seed the
2904 * editable comboboxes, and shows what is in force rather than what is stored. */
2906 self, (const dt_iop_lensfun_params_t *)self->params);
2907
2908 gchar *fm;
2909 const char *maker, *model;
2910 unsigned i;
2911 gdouble focal_values[]
2912 = { -INFINITY, 4.5, 8, 10, 12, 14, 15, 16, 17, 18, 20, 24, 28, 30, 31, 35,
2913 38, 40, 43, 45, 50, 55, 60, 70, 75, 77, 80, 85, 90, 100, 105, 110,
2914 120, 135, 150, 200, 210, 240, 250, 300, 400, 500, 600, 800, 1000, INFINITY };
2915 gdouble aperture_values[]
2916 = { -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,
2917 5.6, 6.3, 7.1, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 29, 32, 38, INFINITY };
2918
2919 ls_db_t *db = _ls_db();
2920 ls_lens_t lens_v;
2921 char l_maker[128] = "", l_model[256] = "";
2922 float min_focal = 0.f, max_focal = 0.f, min_ap = 0.f, max_ap = 0.f;
2923 const gboolean have = (lens_id >= 0) && !IS_NULL_PTR(db)
2924 && (ls_db_lens_by_id(db, lens_id, &lens_v) == 1)
2925 && (ls_db_lens_name(db, lens_id, l_maker, sizeof(l_maker),
2926 l_model, sizeof(l_model)) > 0);
2927 if(have) ls_db_lens_range(db, lens_id, &min_focal, &max_focal, &min_ap, &max_ap);
2928
2929 /* Which sources exist is a property of the lens, so it is re-decided HERE and not only
2930 * when the image is loaded: picking a different lens from the menu is exactly the moment
2931 * a database profile appears or disappears. Without this the panel kept whatever rows the
2932 * image arrived with, and choosing a lens the database does know left every axis still
2933 * offering nothing. */
2934 if(!have)
2935 {
2936 /* Nothing is disabled on this path. Availability is expressed by which ROWS a picker
2937 * holds, never by whether the picker is sensitive -- greying the whole widget withdrew
2938 * the two sources that need no database entry at all, the file's own embedded profile
2939 * and hand-typed TCA coefficients, which is precisely what a lens the database has
2940 * never heard of is left with. */
2943 return;
2944 }
2945
2946 maker = l_maker[0] ? l_maker : NULL;
2947 model = l_model[0] ? l_model : NULL;
2948
2949 if(model)
2950 {
2951 if(maker)
2952 fm = g_strdup_printf("%s, %s", maker, model);
2953 else
2954 fm = g_strdup_printf("%s", model);
2956 dt_free(fm);
2957 }
2958
2959 char focal[100], aperture[100], mounts[200];
2960
2961 if(min_focal < max_focal)
2962 snprintf(focal, sizeof(focal), "%g-%gmm", min_focal, max_focal);
2963 else
2964 snprintf(focal, sizeof(focal), "%gmm", min_focal);
2965 if(min_ap < max_ap)
2966 snprintf(aperture, sizeof(aperture), "%g-%g", min_ap, max_ap);
2967 else
2968 snprintf(aperture, sizeof(aperture), "%g", min_ap);
2969
2970 mounts[0] = 0;
2971 ls_db_lens_mounts(db, lens_id, mounts, sizeof(mounts));
2972
2973 fm = g_strdup_printf(_("maker:\t\t%s\n"
2974 "model:\t\t%s\n"
2975 "focal range:\t%s\n"
2976 "aperture:\t%s\n"
2977 "crop factor:\t%.1f\n"
2978 "type:\t\t%s\n"
2979 "mounts:\t%s"),
2980 maker ? maker : "?", model ? model : "?", focal, aperture,
2981 lens_v.crop_factor, _lens_type_name((int)lens_v.type), mounts);
2982
2984 dt_free(fm);
2985
2986 /* Create the focal/aperture/distance combo boxes */
2988
2989 int ffi = 1, fli = -1;
2990 for(i = 1; i < sizeof(focal_values) / sizeof(gdouble) - 1; i++)
2991 {
2992 if(focal_values[i] < min_focal) ffi = i + 1;
2993 if(focal_values[i] > max_focal && fli == -1) fli = i;
2994 }
2996 {
2997 focal_values[ffi - 1] = min_focal;
2998 ffi--;
2999 }
3000 if(max_focal == 0 || fli < 0) fli = sizeof(focal_values) / sizeof(gdouble) - 2;
3001 if(focal_values[fli + 1] < max_focal)
3002 {
3003 focal_values[fli + 1] = max_focal;
3004 ffi++;
3005 }
3006 if(fli < ffi) fli = ffi + 1;
3007
3008 GtkWidget *w;
3009 char txt[30];
3010
3011 // focal length
3014 gtk_widget_set_tooltip_text(w, _("focal length (mm)"));
3015 snprintf(txt, sizeof(txt), "%.*f", precision(p->focal, 10.0), p->focal);
3017 for(int k = 0; k < fli - ffi; k++)
3018 {
3019 snprintf(txt, sizeof(txt), "%.*f", precision(focal_values[ffi + k], 10.0), focal_values[ffi + k]);
3021 }
3023 gtk_box_pack_start(GTK_BOX(g->lens_param_box), w, TRUE, TRUE, 0);
3025 g->cbe[0] = w;
3026
3027 // f-stop
3028 ffi = 1, fli = sizeof(aperture_values) / sizeof(gdouble) - 1;
3029 for(i = 1; i < sizeof(aperture_values) / sizeof(gdouble) - 1; i++)
3030 if(aperture_values[i] < min_ap) ffi = i + 1;
3032 {
3033 aperture_values[ffi - 1] = min_ap;
3034 ffi--;
3035 }
3036
3039 gtk_widget_set_tooltip_text(w, _("f-number (aperture)"));
3040 snprintf(txt, sizeof(txt), "%.*f", precision(p->aperture, 10.0), p->aperture);
3042 for(int k = 0; k < fli - ffi; k++)
3043 {
3044 snprintf(txt, sizeof(txt), "%.*f", precision(aperture_values[ffi + k], 10.0), aperture_values[ffi + k]);
3046 }
3048 gtk_box_pack_start(GTK_BOX(g->lens_param_box), w, TRUE, TRUE, 0);
3050 g->cbe[1] = w;
3051
3054 gtk_widget_set_tooltip_text(w, _("distance to subject"));
3055 snprintf(txt, sizeof(txt), "%.*f", precision(p->distance, 10.0), p->distance);
3057 float val = 0.25f;
3058 for(int k = 0; k < 25; k++)
3059 {
3060 if(val > 1000.0f) val = 1000.0f;
3061 snprintf(txt, sizeof(txt), "%.*f", precision(val, 10.0), val);
3063 if(val >= 1000.0f) break;
3064 val *= sqrtf(2.0f);
3065 }
3067 gtk_box_pack_start(GTK_BOX(g->lens_param_box), w, TRUE, TRUE, 0);
3069 g->cbe[2] = w;
3070
3071 gtk_widget_show_all(g->lens_param_box);
3072
3073 /* Last, because the rows are read out of the params, which a caller acting on user input
3074 * has already written through _lens_params_set_lens(). */
3077}
3078
3079static void lens_menu_select(GtkMenuItem *menuitem, gpointer user_data)
3080{
3081 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
3082
3083 if(dt_gui_widgets_suppressed()) return;
3084
3087 const long long lens_id =
3088 (long long)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), "lens-id"));
3089
3090 /* Parameters first: both the autoscale below and the row rebuild inside lens_set() ask
3091 * the database what THIS lens offers, and they read it out of the params. */
3092 _lens_params_set_lens(self, lens_id);
3093 p->modified = 1;
3094 p->scale = get_autoscale(self, p);
3095
3096 {
3097 /* Widget writes, not user input. Without the freeze dt_bauhaus_slider_set() emits
3098 * value-changed, whose default callback writes the field again and commits a SECOND
3099 * history item for the one lens the user picked. */
3101 lens_set(self, lens_id);
3102 dt_bauhaus_slider_set(g->scale, p->scale);
3103 }
3104
3105 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
3106}
3107
3108static void lens_menu_fill(dt_iop_module_t *self, const long long *ids, int n)
3109{
3112
3113 if(g->lens_menu)
3114 {
3115 gtk_widget_destroy(GTK_WIDGET(g->lens_menu));
3116 g->lens_menu = NULL;
3117 }
3118
3119 ls_db_t *db = _ls_db();
3120 if(IS_NULL_PTR(db)) return;
3121
3122 /* Count all existing lens makers and create a sorted list */
3125 for(int i = 0; i < n; i++)
3126 {
3127 char maker[128] = "", model[256] = "";
3128 if(ls_db_lens_name(db, ids[i], maker, sizeof(maker), model, sizeof(model)) <= 0) continue;
3129
3130 GtkWidget *submenu, *item;
3132 if(idx < 0)
3133 {
3134 /* No such maker yet, insert it into the array. Owned strings: these no longer point
3135 * into a database that outlives the menu. */
3137 /* Create a submenu for lenses by this maker */
3140 }
3141
3143 /* Append current lens name to the submenu */
3145 gtk_widget_show(item);
3146 g_object_set_data(G_OBJECT(item), "lens-id", GINT_TO_POINTER((gint)ids[i]));
3147 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(lens_menu_select), self);
3149 }
3150
3151 g->lens_menu = GTK_MENU(gtk_menu_new());
3152 for(unsigned i = 0; i < makers->len; i++)
3153 {
3155 gtk_widget_show(item);
3156 gtk_menu_shell_append(GTK_MENU_SHELL(g->lens_menu), item);
3158 }
3159
3162}
3163
3175static long long *_lens_ids_for_camera(dt_iop_module_t *self, const char *model, int *out_n)
3176{
3177 *out_n = 0;
3179 ls_db_t *db = _ls_db();
3180 if(IS_NULL_PTR(db)) return NULL;
3181
3182 ls_camera_t cam;
3183 const gboolean have_cam = (g->camera_id >= 0) && (ls_db_camera_by_id(db, g->camera_id, &cam) == 1);
3184
3185 if(model && model[0])
3186 {
3187 enum { MAX_HITS = 32 };
3189 const int n = ls_db_match_lens(db, NULL, model, have_cam ? cam.mount_id : 0,
3190 have_cam ? cam.crop_factor : 0.f, m, MAX_HITS);
3191 if(n <= 0) return NULL;
3192 long long *ids = (long long *)dt_alloc_align(sizeof(long long) * (size_t)n);
3193 if(IS_NULL_PTR(ids)) return NULL;
3194 for(int i = 0; i < n; i++) ids[i] = m[i].lens_id;
3195 *out_n = n;
3196 return ids;
3197 }
3198
3199 /* Everything that fits the camera's mount, or the whole catalogue when no camera is
3200 * selected -- which is what upstream answered for a NULL camera too. */
3201 const int total = ls_db_list_lenses(db, NULL, 0);
3202 if(total <= 0) return NULL;
3203 long long *all = (long long *)dt_alloc_align(sizeof(long long) * (size_t)total);
3204 if(IS_NULL_PTR(all)) return NULL;
3205 const int got = ls_db_list_lenses(db, all, total);
3206
3207 if(!have_cam)
3208 {
3209 *out_n = got;
3210 return all;
3211 }
3212
3213 int keep = 0;
3214 for(int i = 0; i < got; i++)
3215 if(ls_db_lens_fits_mount(db, all[i], cam.mount_id) == 1) all[keep++] = all[i];
3216 *out_n = keep;
3217 return all;
3218}
3219
3220static void lens_menusearch_clicked(GtkWidget *button, gpointer user_data)
3221{
3222 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
3224 (void)button;
3225
3226 int n = 0;
3227 long long *ids = _lens_ids_for_camera(self, NULL, &n);
3228 if(IS_NULL_PTR(ids)) return;
3229 lens_menu_fill(self, ids, n);
3230 dt_free_align(ids);
3231
3233}
3234
3235
3236/* -- end lens -- */
3237
3238static void target_geometry_changed(GtkWidget *widget, gpointer user_data)
3239{
3240 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
3242
3243 int pos = dt_bauhaus_combobox_get(widget);
3244 p->target_geom = (dt_lens_type_t)(pos + DT_LENS_UNKNOWN + 1);
3245 p->modified = 1;
3246 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
3247}
3248
3258/* Defined further down, next to the data they work on. */
3260 const dt_lens_source_t source);
3262 const dt_iop_lensfun_params_t *const p);
3263
3279
3280
3293 const dt_lens_axis_t axis)
3294{
3295 const dt_lens_source_t source = _lens_source_get(p, axis);
3296 return (_lens_source_row(g, axis, source) >= 0) ? source : DT_LENS_SOURCE_OFF;
3297}
3298
3300{
3302 self, (const dt_iop_lensfun_params_t *)self->params);
3304 if(IS_NULL_PTR(g)) return;
3305
3308
3309 /* Projection and scaling are the other two thirds of the distortion pack, so they appear
3310 * exactly when that pack runs. Leaving the scale slider visible while it does nothing was
3311 * the same defect as the hidden geometry combobox that kept applying -- a control and its
3312 * effect disagreeing -- just the other way round. */
3313 /* Scaling belongs to the pack, so it shows whenever the pack runs -- from either source.
3314 * Projection does not: changing the lens's projection is a property of the database's
3315 * model, and a maker's profile describes the lens in the projection it shipped with. */
3318
3321
3322 /* Soft deprecation of the distort/correct mode: shown only to an edit that already uses
3323 * it, so nobody loses a setting they made, and offered to nobody else. The module is
3324 * called lens correction; deliberately ADDING a lens's flaws is not something anyone has
3325 * been found to want, and the row cost more panel than the feature was worth. */
3326 gtk_widget_set_visible(g->reverse, p->inverse != 0);
3327
3328 /* Which sources this image can actually offer is decided in _lens_rebuild_axis_rows(),
3329 * which runs from gui_update() and from every setter that changes what the database can
3330 * match: a source with nothing behind it gets no row at all. Greying was not enough --
3331 * bauhaus honours entry sensitivity when the list is scrolled but not when a row is
3332 * clicked, so a greyed row was still selectable and still did nothing. Nor is greying the
3333 * whole picker: OFF and manual TCA are available to every image, database or not. */
3334}
3335
3336/* What each source is called in the panel. Indexed by dt_lens_source_t, so the name and
3337 * the value cannot drift apart the way two parallel lists would.
3338 *
3339 * The two that ARE profiles say whose measurement they are, because that is the choice the
3340 * user is actually making: the camera maker measured this body with this lens on a bench,
3341 * while the database is a community measurement of that lens model. "Embedded" and
3342 * "database" described where the numbers were stored, which is the one thing about them
3343 * nobody needs to know. The other two are not profiles and do not pretend to be. */
3344static const char *const _lens_source_names[DT_LENS_SOURCE_LAST] = {
3345 [DT_LENS_SOURCE_OFF] = N_("no correction"),
3346 [DT_LENS_SOURCE_LENSFUN] = N_("community profile"),
3347 [DT_LENS_SOURCE_EMBEDDED] = N_("vendor profile"),
3348 [DT_LENS_SOURCE_MANUAL] = N_("manual correction"),
3349};
3350
3351/* Which sources one axis's combobox offers, in the order they appear. OFF is always first
3352 * and LENSFUN always second, so a row's index means the same thing on every axis and the
3353 * user is not re-learning the widget three times. */
3362
3371 const dt_lens_source_t source)
3372{
3373 for(int i = 0; i < g->axis_rows[axis]; i++)
3374 if(g->axis_row[axis][i] == source) return i;
3375 return -1;
3376}
3377
3395{
3397 self, (const dt_iop_lensfun_params_t *)self->params);
3399 if(IS_NULL_PTR(g)) return;
3400
3401 const int offers = _lens_database_offers(self, p);
3402
3403 /* A monochrome sensor has no colour channels to shift against each other, so lateral CA
3404 * is not a correction that exists for this image at all -- _lens_mask_for_mono() already
3405 * withdraws it from every pipe. Offering it here would be a row that renders nothing,
3406 * which is the one thing the per-image row list exists to prevent. */
3407 const gboolean mono = !IS_NULL_PTR(self->dev)
3409
3410 {
3411 GtkWidget *w = g->axis_source[axis];
3412 int n = 0;
3413
3414 /* Filling a combobox is a programmatic update, and _lens_axis_source_changed() must not
3415 * mistake it for the user picking a row: it commits to history. Two callers are already
3416 * outside gui_update()'s own freeze -- the distortion handler rebuilding the TCA row,
3417 * and lens_set() rebuilding everything when the lens changes -- so the freeze belongs
3418 * here, where the widget is actually written, rather than at each call site. */
3420
3422 for(int i = 0; i < DT_LENS_SOURCE_LAST; i++)
3423 {
3425 if(src == DT_LENS_SOURCE_LAST) break;
3426
3427 gboolean have;
3428 switch(src)
3429 {
3430 case DT_LENS_SOURCE_OFF: have = TRUE; break;
3433 have = _lens_image_embeds(self, axis);
3434 /* A maker's aberration is measured against their OWN geometry, so it is offered
3435 * only when the geometry is theirs too. Stacking it on a database distortion
3436 * would be two calibrations of one lens applied to each other -- and the
3437 * evaluator cannot express it either: the table's CA lives in the same curve as
3438 * its distortion. The other direction is fine and supported: the table's geometry
3439 * happily wears a database or hand-typed aberration. */
3442 have = FALSE;
3443 break;
3444 case DT_LENS_SOURCE_MANUAL: have = (axis == DT_LENS_AXIS_TCA); break;
3445 default: have = FALSE; break;
3446 }
3447 if(mono && axis == DT_LENS_AXIS_TCA && src != DT_LENS_SOURCE_OFF) have = FALSE;
3448 if(!have) continue;
3449
3451 g->axis_row[axis][n++] = src;
3452 }
3453 g->axis_rows[axis] = n;
3454
3455 /* Show what the params say, or fall back to OFF -- which is row 0 and always there.
3456 * A stored source this image cannot supply has no row to select, and the correction
3457 * would not have run either; commit_params has already said so. */
3459 if(row < 0) row = 0;
3461 }
3462}
3463
3470
3471
3474 const GtkWidget *w)
3475{
3477 if(g->axis_source[axis] == w) return axis;
3478 return DT_LENS_AXIS_LAST;
3479}
3480
3481static void _lens_axis_source_changed(GtkWidget *widget, gpointer user_data)
3482{
3483 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
3484 if(dt_gui_widgets_suppressed()) return;
3487
3488 const dt_lens_axis_t axis = _lens_axis_of_widget(g, widget);
3489 if(axis == DT_LENS_AXIS_LAST) return;
3490
3491 /* Against what the widget currently holds, not the catalogue: rows the image cannot
3492 * supply are absent, so a catalogue index would name the wrong source. */
3493 const int row = dt_bauhaus_combobox_get(widget);
3494 if(row < 0 || row >= g->axis_rows[axis]) return;
3495
3496 const dt_lens_source_t source = g->axis_row[axis][row];
3497
3498 _lens_source_set(p, axis, source);
3499 p->modified = 1;
3500
3501 /* Distortion decides whether the maker's aberration may be offered, so its rows move when
3502 * distortion does. Rebuilding a DIFFERENT axis's widget from this handler is safe;
3503 * rebuilding the one being handled would not be. */
3505
3507 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
3508}
3509
3517 const dt_lens_axis_t axis, const char *label,
3518 const char *tooltip)
3519{
3521 g->axis_source[axis] = w;
3524 gtk_box_pack_start(GTK_BOX(self->gui->widget), w, TRUE, TRUE, 0);
3525
3526 /* Left empty: the rows depend on the image, and gui_update() fills them. */
3527 g->axis_rows[axis] = 0;
3528 g_signal_connect(G_OBJECT(w), "value-changed",
3529 G_CALLBACK(_lens_axis_source_changed), (gpointer)self);
3530 return w;
3531}
3532
3533void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
3534{
3536
3537 /* Which controls are visible is decided in ONE place, _lens_gui_update_sensitivity(), out
3538 * of the sources the pickers are actually showing. It used to be decided here as well,
3539 * out of p->tca_override and the monochrome flag, and the two could disagree: this runs
3540 * LAST out of gui_update() and so had the final word, putting the manual coefficient
3541 * sliders back on screen for an image whose TCA picker was not offering manual at all. */
3542 if(w)
3543 {
3544 // user did modify something with some widget
3545 p->modified = 1;
3546 }
3547}
3548
3549
3551{
3552 float scale = 1.0f;
3553
3554 /* Built by THE constructor, not by hand. The hand-rolled version resolved only the
3555 * database lens, so with distortion taking the maker's embedded profile this measured a
3556 * correction the pipe was not applying -- and the result was then multiplied ON TOP of
3557 * the profile's own autoscale by get_modifier(), giving a doubled zoom. It also returned
3558 * 1.0 outright when no database lens matched, which is precisely the body an embedded
3559 * profile exists to serve. */
3561 memset(&d, 0, sizeof(d));
3562 _lens_build_data(self, p, &d);
3563 if(!_lens_data_available(&d)) return scale;
3564
3565 /* Measure the correction itself, not a scaling already applied to it. For the embedded
3566 * resolver this leaves the profile's own autoscale in place and asks what is still needed
3567 * on top of it -- which is what get_modifier() then composes. */
3568 d.scale = 1.0f;
3569
3570 const dt_image_t *img = &(self->dev->image_storage);
3571 // FIXME: get those from rawprepare IOP somehow !!!
3572 const int iwd = img->width - img->crop_x - img->crop_width,
3573 iht = img->height - img->crop_y - img->crop_height;
3574
3575 ls_modifier_t modifier;
3576 if(get_modifier(NULL, iwd, iht, &d, DT_LENS_MODIFY_ALL_AXES, FALSE, &modifier, NULL))
3577 scale = ls_modifier_autoscale(&modifier);
3578 return scale;
3579}
3580
3581static void autoscale_pressed(GtkWidget *button, gpointer user_data)
3582{
3583 dt_iop_module_t *self = (dt_iop_module_t *)user_data;
3586 const float scale = get_autoscale(self, p);
3587 p->modified = 1;
3588 dt_bauhaus_slider_set(g->scale, scale);
3589 dt_dev_add_history_item(self->dev, self, TRUE, TRUE);
3590}
3591
3609 const dt_iop_lensfun_params_t *const p)
3610{
3611 if(IS_NULL_PTR(self->dev)) return 0;
3612
3614 memset(&d, 0, sizeof(d));
3615 _lens_build_data(self, p, &d);
3616 if(!_lens_data_available(&d)) return 0;
3617
3618 /* The frame the correction is expressed over. Only its aspect matters to which axes
3619 * resolve, so the full image is a fine stand-in when the pipe has not published one. */
3620 dt_iop_roi_t roi = { 0, 0, 0, 0, 1.f };
3621 if(!dt_dev_module_geometry_gui(self->dev, self, &roi, NULL) || roi.width <= 0
3622 || roi.height <= 0)
3623 {
3624 const dt_image_t *img = &self->dev->image_storage;
3625 roi.width = img->width;
3626 roi.height = img->height;
3627 }
3628 if(roi.width <= 0 || roi.height <= 0) return 0;
3629
3631 int modflags = 0;
3633 get_modifier(&modflags, roi.width, roi.height, &d, mask, FALSE, &m, NULL);
3635}
3636
3637
3638void gui_init(struct dt_iop_module_t *self)
3639{
3641
3642 g->camera_id = -1;
3643 g->camera_menu = NULL;
3644 g->lens_menu = NULL;
3645
3646
3648 gtk_widget_set_name(self->gui->widget, "lens-module");
3649
3650 /* One button per row, not two. Each row used to carry a second, unlabelled arrow that
3651 * listed the Exif match instead of the whole catalogue -- for the camera, a menu of
3652 * exactly one entry, the one reload_defaults() had already applied.
3653 *
3654 * Filtering these lists by Exif is useless by construction: they are opened precisely
3655 * BECAUSE Exif matching failed. A lens with no CPU reports no lens at all, so there is
3656 * nothing to filter on; a body absent from the database is chosen by picking a near
3657 * relative deliberately -- a Mk I for a Mk II -- which an Exif filter would never
3658 * suggest. Both cases want the full list, which is what the model button has always
3659 * shown. */
3660
3661 // camera selector
3663 g->camera_model = dt_iop_button_new(self, N_("camera model"),
3664 G_CALLBACK(camera_menusearch_clicked), FALSE, 0, (GdkModifierType)0,
3665 NULL, 0, hbox);
3666 gtk_box_pack_start(GTK_BOX(self->gui->widget), hbox, TRUE, TRUE, 0);
3667
3668 // lens selector
3670 g->lens_model = dt_iop_button_new(self, N_("lens model"),
3671 G_CALLBACK(lens_menusearch_clicked), FALSE, 0, (GdkModifierType)0,
3672 NULL, 0, hbox);
3673 gtk_box_pack_start(GTK_BOX(self->gui->widget), hbox, TRUE, TRUE, 0);
3674
3675 // lens properties
3677 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->lens_param_box, TRUE, TRUE, 0);
3678
3679
3680 /* The panel reads top to bottom as: what was detected, how much to rescale, then one
3681 * section per correction axis. Each section is its source combobox followed by exactly
3682 * the controls that source uses -- geometry under distortion, the manual coefficients
3683 * under TCA -- so a control is never far from the thing that decides whether it applies.
3684 *
3685 * That is why these are written out one at a time rather than looped: the loop would have
3686 * to put every axis's extra controls somewhere else, and "somewhere else" is how the old
3687 * panel ended up with a TCA override checkbox three rows away from the TCA setting. */
3688
3689 // 2. vignetting
3691 N_("correct the lens's light falloff, and where to take it from"));
3692
3693 // 3. distortion, with the projection and the scaling that go with it
3695 N_("correct the lens's geometric distortion, and where to take it from"));
3696
3698 dt_bauhaus_widget_set_label(g->target_geom, N_("geometry"));
3699 gtk_box_pack_start(GTK_BOX(self->gui->widget), g->target_geom, TRUE, TRUE, 0);
3700 gtk_widget_set_tooltip_text(g->target_geom, _("target geometry"));
3701 dt_bauhaus_combobox_add(g->target_geom, _("rectilinear"));
3702 dt_bauhaus_combobox_add(g->target_geom, _("fish-eye"));
3703 dt_bauhaus_combobox_add(g->target_geom, _("panoramic"));
3704 dt_bauhaus_combobox_add(g->target_geom, _("equirectangular"));
3705 dt_bauhaus_combobox_add(g->target_geom, _("orthographic"));
3706 dt_bauhaus_combobox_add(g->target_geom, _("stereographic"));
3707 dt_bauhaus_combobox_add(g->target_geom, _("equisolid angle"));
3708 dt_bauhaus_combobox_add(g->target_geom, _("thoby fish-eye"));
3709 g_signal_connect(G_OBJECT(g->target_geom), "value-changed", G_CALLBACK(target_geometry_changed),
3710 (gpointer)self);
3711
3712 /* Scaling closes the distortion section rather than opening the module. It is the third
3713 * of the pack -- distortion, projection, scale -- and it only ever runs when that pack
3714 * runs, so putting it at the top left the user reading a control whose effect lived four
3715 * rows further down, under a different heading. */
3716 g->scale = dt_bauhaus_slider_from_params(self, N_("scale"));
3719 g_signal_connect(G_OBJECT(g->scale), "quad-pressed", G_CALLBACK(autoscale_pressed), self);
3720 gtk_widget_set_tooltip_text(g->scale, _("auto scale"));
3721
3722 // 4. chromatic aberrations, and the coefficients the manual source uses
3723 _lens_add_axis_combobox(self, g, DT_LENS_AXIS_TCA, N_("chromatic aberrations"),
3724 N_("correct lateral chromatic aberration, and where to take it from"));
3725
3726 /* p->tca_override has NO widget. It survives only as storage -- _lens_source_set()
3727 * writes it whenever TCA is set to manual, so an edit saved by this version is still read
3728 * correctly by one that predates the per-axis sources. The checkbox it used to drive is
3729 * gone: "TCA = manual correction" is a row of the combobox above, and one state behind two
3730 * controls is one state they can disagree about. */
3731
3732 g->tca_r = dt_bauhaus_slider_from_params(self, "tca_r");
3734 gtk_widget_set_tooltip_text(g->tca_r, _("Transversal Chromatic Aberration red"));
3735
3736 g->tca_b = dt_bauhaus_slider_from_params(self, "tca_b");
3738 gtk_widget_set_tooltip_text(g->tca_b, _("Transversal Chromatic Aberration blue"));
3739
3740 /* Last, because it is on its way out: it inverts every axis at once, nobody has been
3741 * found who uses it, and it is kept only so existing edits that set it keep rendering. */
3742 g->reverse = dt_bauhaus_combobox_from_params(self, "inverse");
3743 dt_bauhaus_combobox_add(g->reverse, _("correct"));
3744 dt_bauhaus_combobox_add(g->reverse, _("distort"));
3745 gtk_widget_set_tooltip_text(g->reverse, _("correct distortions or apply them"));
3746
3747
3748}
3749
3750void gui_update(struct dt_iop_module_t *self)
3751{
3752 // let gui elements reflect params
3754
3755 /* What is actually IN FORCE, which for an edit saved with modified == 0 is default_params
3756 * rather than params -- see _lens_effective_params(). The view shows that; it does not
3757 * write it back. This function used to memcpy default_params over self->params right
3758 * here, which mutated an edit from a panel refresh, and did not even reach the widgets it
3759 * was meant to fix: dt_iop_gui_update() runs dt_bauhaus_update_module() out of
3760 * self->params BEFORE calling this, so the copy only ever showed up one refresh late. */
3762 self, (const dt_iop_lensfun_params_t *)self->params);
3763
3764 // these are the wrong (untranslated) strings in general but that's ok, they will be overwritten further
3765 // down
3766 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->camera_model))), p->camera);
3768 gtk_widget_set_tooltip_text(g->camera_model, "");
3769 gtk_widget_set_tooltip_text(g->lens_model, "");
3770
3773
3774 /* dt_bauhaus_update_module() has already synced these from self->params. Re-set them from
3775 * the effective params so a modified == 0 edit shows what it renders rather than what it
3776 * stores; for every other edit the two are the same object and this is a no-op. */
3777 dt_bauhaus_combobox_set(g->target_geom, p->target_geom - DT_LENS_UNKNOWN - 1);
3778 dt_bauhaus_combobox_set(g->reverse, p->inverse);
3779 dt_bauhaus_slider_set(g->scale, p->scale);
3780 dt_bauhaus_slider_set(g->tca_r, p->tca_r);
3781 dt_bauhaus_slider_set(g->tca_b, p->tca_b);
3782
3783 g->camera_id = -1;
3784 if(p->camera[0])
3785 {
3786 /* Resolved the same way the pipeline resolves it. Recovering the id by comparing the
3787 * params string against stored model names cannot work: matching is on the normalised
3788 * form, so "NIKON D5300" finds a row whose model column reads "D5300" -- which is why
3789 * this label was blank on every image while the correction itself was applied. */
3790 ls_camera_t cam;
3791 camera_set(self, _ls_find_camera(NULL, p->camera, &cam) ? cam.id : -1);
3792 }
3793 if(g->camera_id >= 0 && p->lens[0])
3794 {
3795 char model[200];
3796 parse_model(p->lens, model, sizeof(model));
3797 int n = 0;
3798 long long *ids = _lens_ids_for_camera(self, model[0] ? model : NULL, &n);
3799 lens_set(self, (n > 0 && !IS_NULL_PTR(ids)) ? ids[0] : -1);
3800 if(!IS_NULL_PTR(ids)) dt_free_align(ids);
3801 }
3802 else
3803 {
3804 lens_set(self, -1);
3805 }
3806
3807
3808
3809 gui_changed(self, NULL, NULL);
3810}
3811
3813{
3814
3816}
3817
3818
3819// clang-format off
3820// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
3821// vim: shiftwidth=2 expandtab tabstop=2 cindent
3822// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
3823// clang-format on
static double dist(double x1, double y1, double x2, double y2)
Definition ashift_lsd.c:250
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:283
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
Definition bauhaus.c:3343
void dt_bauhaus_combobox_clear(GtkWidget *widget)
Definition bauhaus.c:1997
void dt_bauhaus_combobox_set_editable(GtkWidget *widget, int editable)
Definition bauhaus.c:1882
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
Definition bauhaus.c:1970
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3331
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2090
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1504
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1698
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1824
void dt_bauhaus_widget_set_quad_paint(GtkWidget *widget, dt_bauhaus_quad_paint_f f, int paint_flags, void *paint_data)
Definition bauhaus.c:1554
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
@ IOP_CS_RGB
static const float x
const float v
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
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)))
static const int row
gboolean dt_image_is_monochrome(const dt_image_t *img)
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
Definition darktable.c:508
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_iop_params_t
Definition dev_history.h:43
gboolean dt_dev_module_geometry_gui(dt_develop_t *dev, dt_iop_module_t *module, dt_iop_roi_t *in, dt_iop_roi_t *out)
One module's own input and output rectangles at full resolution, from the geometry service.
Definition develop.c:1771
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
Definition develop.h:123
GtkWidget * status
result of the last capture
void dt_loc_get_datadir(char *datadir, size_t bufsize)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
Where things are on the image, answered without a pipeline.
#define DT_GUI_MODULE(x)
const char * tooltip
Definition image.h:310
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:91
void dt_iop_compute_module_hash(dt_iop_module_t *module, GList *masks)
Definition imageop.c:1461
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
Definition imageop.c:1909
@ IOP_FLAGS_ALLOW_TILING
Definition imageop.h:188
@ IOP_FLAGS_UNSAFE_COPY
Definition imageop.h:196
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:190
@ IOP_GROUP_REPAIR
Definition imageop.h:159
@ IOP_TAG_DISTORT
Definition imageop.h:170
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_slider_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
#define IOP_GUI_FREE
Definition imageop_gui.h:96
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
Definition imageop_gui.h:81
#define IOP_GUI_ALLOC(module)
Definition imageop_gui.h:93
void *const ovoid
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 dt_dev_pixelpipe_t * pipe
Definition layers.h:49
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t * piece
Definition layers.h:50
static const dt_iop_drawlayer_params_t * params
Definition layers.h:80
int operation_tags()
Definition lens.c:939
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.c:1796
#define DT_LENS_MODIFY_ANSEL_MASK
Definition lens.c:196
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.c:2223
static const char *const _lens_source_names[DT_LENS_SOURCE_LAST]
Definition lens.c:3344
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.c:1830
static long long * _camera_all_ids(int *out_n)
Every camera in the database, as ids the caller must free with dt_free_align().
Definition lens.c:2787
const char ** description(struct dt_iop_module_t *self)
Definition lens.c:924
int default_group()
Definition lens.c:934
static void _lens_rebuild_axis_rows(dt_iop_module_t *self)
Every axis, for a fresh image.
Definition lens.c:3465
static const char * _lens_type_name(int type)
A projection's name, replacing lfLens::GetLensTypeDesc().
Definition lens.c:2862
static void _lens_fill_vignette_row(float *const buf, const int width, const int ch)
Definition lens.c:1311
static int _lens_used_mask(dt_iop_module_t *self)
The lensfun modify mask this image allows: monochrome sensors get no TCA correction.
Definition lens.c:2218
static void _lens_build_data(dt_iop_module_t *self, const dt_iop_lensfun_params_t *const p, dt_iop_lensfun_data_t *d)
Build the lensfun state from resolved parameters. THE constructor.
Definition lens.c:2037
static int ptr_array_find_sorted(const GPtrArray *array, const void *item, GCompareFunc compare)
Definition lens.c:2563
static gboolean _lens_source_is_library_served(const dt_lens_source_t source)
Is this source served by the LensSerious path, once the data has been prepared?
Definition lens.c:498
static int _lens_mask_for_mono(const gboolean monochrome)
Which axes may be attempted on this image.
Definition lens.c:517
static int _lens_source_row(const dt_iop_lensfun_gui_data_t *g, const dt_lens_axis_t axis, const dt_lens_source_t source)
Show only the controls the current sources actually use.
Definition lens.c:3370
static void _lens_free_data(void *ptr)
Definition lens.c:2255
static void _lens_report_db_failure(const char *path, const ls_db_open_status_t status, const int found_version, const char *detail)
This thread's database handle, opened on first use.
Definition lens.c:668
static GtkWidget * _lens_add_axis_combobox(dt_iop_module_t *self, dt_iop_lensfun_gui_data_t *g, const dt_lens_axis_t axis, const char *label, const char *tooltip)
Build one axis's source combobox and pack it at the end of the module.
Definition lens.c:3516
void reload_defaults(dt_iop_module_t *module)
Definition lens.c:2364
static int _lens_axis_presence_bit(const dt_lens_axis_t axis)
The single bit that says whether an axis is on.
Definition lens.c:349
static int _lens_axis_shift(const dt_lens_axis_t axis)
How far up modify_flags this axis's two source bits sit.
Definition lens.c:355
dt_lens_modify_t
What modify_flags holds, bit by bit.
Definition lens.c:167
@ DT_LENS_MODIFY_GEOMETRY
Definition lens.c:172
@ DT_LENS_MODIFY_VIGNETTING
Definition lens.c:170
@ DT_LENS_SOURCE_SHIFT_VIGNETTING
Definition lens.c:178
@ DT_LENS_MODIFY_SCALE
Definition lens.c:173
@ DT_LENS_MODIFY_DISTORTION
Definition lens.c:171
@ DT_LENS_SOURCE_BITS
Definition lens.c:179
@ DT_LENS_SOURCE_SHIFT_TCA
Definition lens.c:176
@ DT_LENS_SOURCE_SHIFT_DISTORTION
Definition lens.c:177
@ DT_LENS_MODIFY_TCA
Definition lens.c:169
dt_lens_source_t
Where one axis takes its correction from. The same vocabulary for all three.
Definition lens.c:251
@ DT_LENS_SOURCE_MANUAL
Definition lens.c:255
@ DT_LENS_SOURCE_LAST
Definition lens.c:256
@ DT_LENS_SOURCE_LENSFUN
Definition lens.c:253
@ DT_LENS_SOURCE_EMBEDDED
Definition lens.c:254
@ DT_LENS_SOURCE_OFF
Definition lens.c:252
static void lens_comboentry_distance_update(GtkWidget *widget, dt_iop_module_t *self)
Definition lens.c:2846
static char * _lens_sanitize(const char *orig_lens)
Definition lens.c:1077
static int _lens_geometry_backtransform(const void *data, const dt_geometry_record_t *const record, dt_geometry_chain_t *chain, float *points, size_t points_count)
Definition lens.c:2301
static const dt_lens_source_t _lens_axis_sources[DT_LENS_AXIS_LAST][DT_LENS_SOURCE_LAST]
Definition lens.c:3354
static void lens_set(dt_iop_module_t *self, long long lens_id)
Show a lens in the panel, and offer the sources it makes available. VIEW ONLY – writes no parameter.
Definition lens.c:2900
static gboolean _lens_flags_move_pixels(const int modify_flags)
Does this flag word describe anything that MOVES pixels?
Definition lens.c:482
static void autoscale_pressed(GtkWidget *button, gpointer user_data)
Definition lens.c:3581
__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.c:1336
static ls_db_t * _ls_db(void)
Definition lens.c:708
static int _lens_corrections_available(dt_iop_module_t *self, const dt_iop_lensfun_params_t *const p)
Which corrections this configuration will actually apply.
Definition lens.c:3608
static void camera_menu_select(GtkMenuItem *menuitem, gpointer user_data)
Definition lens.c:2686
static const dt_geometry_vtable_t _lens_geometry_vtable
Definition lens.c:2307
static gboolean _ls_find_camera(const char *maker, const char *model, ls_camera_t *out)
The camera an EXIF maker/model names.
Definition lens.c:767
const char * aliases()
Definition lens.c:919
static int _lens_axis_flags(const dt_lens_axis_t axis)
The enable bits for one axis. Three of them for distortion; see the pack.
Definition lens.c:331
static void lens_comboentry_focal_update(GtkWidget *widget, dt_iop_module_t *self)
Definition lens.c:2828
static void camera_menusearch_clicked(GtkWidget *button, gpointer user_data)
Definition lens.c:2809
static gboolean _lens_image_embeds(dt_iop_module_t *self, const dt_lens_axis_t axis)
Does THIS image carry a maker's profile for this axis?
Definition lens.c:536
static void lens_comboentry_aperture_update(GtkWidget *widget, dt_iop_module_t *self)
Definition lens.c:2837
static long long _ls_find_lens(long long mount_id, float crop, float focal, const char *lens_name)
The lens a free-text name names, as an id.
Definition lens.c:829
static void _lens_params_set_lens(dt_iop_module_t *self, const long long lens_id)
Write the lens the user picked into the params. USER INTERACTION ONLY.
Definition lens.c:2885
static void _lens_axis_source_changed(GtkWidget *widget, gpointer user_data)
Definition lens.c:3481
dt_iop_lensfun_modflag_t
Definition lens.c:285
@ LENSFUN_MODFLAG_MASK
Definition lens.c:288
static gboolean _lens_axis_enabled(const dt_iop_lensfun_params_t *p, const dt_lens_axis_t axis)
Is this axis correcting at all, from wherever?
Definition lens.c:468
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition lens.c:2329
static __DT_CLONE_TARGETS__ int get_modifier(int *mods_done, int w, int h, const dt_iop_lensfun_data_t *d, int mods_filter, gboolean force_inverse, ls_modifier_t *mod, ls_modifier_t *vig_mod)
Resolve the lens at one shooting configuration. THE modifier factory.
Definition lens.c:1125
dt_lens_axis_t
The correction axes, as an index rather than a bit – so a caller can loop.
Definition lens.c:226
@ DT_LENS_AXIS_DISTORTION
Definition lens.c:228
@ DT_LENS_AXIS_TCA
Definition lens.c:227
@ DT_LENS_AXIS_VIGNETTING
Definition lens.c:229
@ DT_LENS_AXIS_LAST
Definition lens.c:230
const char * name()
Definition lens.c:914
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.c:1764
static gboolean _lens_source_applicable(const dt_lens_axis_t axis, const dt_lens_source_t source)
Whether source means anything on axis.
Definition lens.c:374
static void ptr_array_insert_index(GPtrArray *array, const void *item, int index)
Definition lens.c:2592
gboolean geometry_record(dt_iop_module_t *self, const void *params, dt_geometry_record_t *record)
Definition lens.c:2313
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
Definition lens.c:3750
static int _lens_geometry_apply(const void *data, const dt_geometry_record_t *const record, float *points, size_t points_count, gboolean inverse)
Apply the correction to points. inverse selects the direction, as get_modifier() means it: distort_tr...
Definition lens.c:2264
static gboolean _lens_flags_have_axis(const int modify_flags, const dt_lens_axis_t axis)
Is this axis present in a flag word – typically get_modifier()'s done?
Definition lens.c:505
static int precision(double x, double adj)
Definition lens.c:2505
void gui_init(struct dt_iop_module_t *self)
Definition lens.c:3638
static void _lens_params_set_camera(dt_iop_module_t *self, const long long camera_id)
Write the camera the user picked into the params. USER INTERACTION ONLY.
Definition lens.c:2616
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
Definition lens.c:3533
static dt_lens_axis_t _lens_axis_of_widget(const dt_iop_lensfun_gui_data_t *g, const GtkWidget *w)
Which axis a combobox belongs to, by widget identity.
Definition lens.c:3473
static long long * _lens_ids_for_camera(dt_iop_module_t *self, const char *model, int *out_n)
The lenses to offer for the camera currently shown, as ids.
Definition lens.c:3175
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.c:1729
static int _lens_database_offers(dt_iop_module_t *self, const dt_iop_lensfun_params_t *p)
Which axes the lens DATABASE could correct for this image, whatever is selected.
Definition lens.c:3272
static void _lens_gui_update_sensitivity(dt_iop_module_t *self)
Definition lens.c:3299
void cleanup_global(dt_iop_module_so_t *module)
Definition lens.c:2484
static int _lens_geometry_transform(const void *data, const dt_geometry_record_t *const record, dt_geometry_chain_t *chain, float *points, size_t points_count)
Definition lens.c:2295
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
Definition lens.c:949
static void lens_menu_fill(dt_iop_module_t *self, const long long *ids, int n)
Definition lens.c:3108
static dt_lens_source_t _lens_source_decode(const int modify_flags, const gboolean tca_override, const dt_lens_axis_t axis)
Decode one axis's source out of a raw flag word.
Definition lens.c:392
int flags()
Definition lens.c:944
static void lens_menusearch_clicked(GtkWidget *button, gpointer user_data)
Definition lens.c:3220
static float get_autoscale(dt_iop_module_t *self, dt_iop_lensfun_params_t *p)
Definition lens.c:3550
static GPrivate _ls_tls_key
Definition lens.c:635
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.c:1899
void gui_cleanup(struct dt_iop_module_t *self)
Definition lens.c:3812
dt_lens_type_t
Definition lens.c:260
@ DT_LENS_RECTILINEAR
Definition lens.c:262
@ DT_LENS_FISHEYE_THOBY
Definition lens.c:269
@ DT_LENS_FISHEYE_EQUISOLID
Definition lens.c:268
@ DT_LENS_FISHEYE_ORTHOGRAPHIC
Definition lens.c:266
@ DT_LENS_UNKNOWN
Definition lens.c:261
@ DT_LENS_FISHEYE
Definition lens.c:263
@ DT_LENS_PANORAMIC
Definition lens.c:264
@ DT_LENS_FISHEYE_STEREOGRAPHIC
Definition lens.c:267
@ DT_LENS_EQUIRECTANGULAR
Definition lens.c:265
static int ptr_array_insert_sorted(GPtrArray *array, const void *item, GCompareFunc compare)
Definition lens.c:2529
static void lens_menu_select(GtkMenuItem *menuitem, gpointer user_data)
Definition lens.c:3079
static void _lens_rebuild_axis_row(dt_iop_module_t *self, const dt_lens_axis_t axis)
Rebuild each axis's combobox to hold exactly the sources THIS image can supply.
Definition lens.c:3394
static gboolean _lens_data_available(const dt_iop_lensfun_data_t *d)
Does this pipe data hold ANY resolvable correction source?
Definition lens.c:908
static void target_geometry_changed(GtkWidget *widget, gpointer user_data)
Definition lens.c:3238
static void parse_model(const char *txt, char *model, size_t sz_model)
Definition lens.c:2800
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
Definition lens.c:2335
static dt_lens_source_t _lens_source_get(const dt_iop_lensfun_params_t *p, const dt_lens_axis_t axis)
Where this axis takes its correction from.
Definition lens.c:415
static dt_lens_source_t _lens_source_displayed(const dt_iop_lensfun_gui_data_t *g, const dt_iop_lensfun_params_t *p, const dt_lens_axis_t axis)
The source the panel is SHOWING for this axis.
Definition lens.c:3291
static void camera_set(dt_iop_module_t *self, long long camera_id)
Show a camera in the panel. VIEW ONLY – writes no parameter.
Definition lens.c:2641
static void delete_children(GtkWidget *widget, gpointer data)
Definition lens.c:2855
static void _ls_tls_free(gpointer data)
Definition lens.c:627
void init_global(dt_iop_module_so_t *module)
Definition lens.c:2346
#define DT_LENS_MODIFY_ALL_AXES
Definition lens.c:206
static gboolean _lens_source_is(const dt_iop_lensfun_params_t *p, const dt_lens_axis_t axis, const dt_lens_source_t source)
Is this axis taking its correction from source?
Definition lens.c:460
static const dt_iop_lensfun_params_t * _lens_effective_params(dt_iop_module_t *self, const dt_iop_lensfun_params_t *const p)
Which parameters are actually in force.
Definition lens.c:2024
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.c:1580
#define DT_LENS_MODIFY_DISTORTION_PACK
The three lensfun axes that always move together, as one flag.
Definition lens.c:192
static _ls_tls_t * _ls_tls_get(void)
This thread's cache block, allocated on first use. NULL only if that allocation failed,...
Definition lens.c:639
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.c:1892
static void _lens_source_set(dt_iop_lensfun_params_t *p, const dt_lens_axis_t axis, dt_lens_source_t source)
Point one axis at a source, leaving every other axis alone.
Definition lens.c:432
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.c:954
static void camera_menu_fill(dt_iop_module_t *self, const long long *ids, int n)
Build the camera picker from a list of database ids.
Definition lens.c:2721
_lib_location_type_t type
Definition location.c:1
@ DT_DEBUG_OPENCL
Definition logging.h:57
@ DT_DEBUG_PIPE
Definition logging.h:76
@ DT_DEBUG_ALWAYS
Definition logging.h:49
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
Definition mem_alloc.h:225
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
Definition mem_alloc.h:80
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
char * key
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
Definition opencl.c:2595
int dt_opencl_create_kernel(const int prog, const char *name)
Definition opencl.c:2489
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:2720
void dt_opencl_free_kernel(const int kernel)
Definition opencl.c:2532
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:2586
#define ROUNDUPDHT(a, b)
Definition opencl.h:86
#define ROUNDUPDWD(a, b)
Definition opencl.h:85
#define __OMP_FOR__(...)
Definition openmp.h:98
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
void dt_concat_path_file(char destination[4096], const char path[4096], const char *const file)
Append a constant filename to a variable, stack-based, fixed-sized, directory, and add a / in-between...
Definition darktable.c:2674
@ DT_DEV_PIXELPIPE_FULL
Definition pixelpipe.h:43
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_get_perthread(buf, padsize)
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
void dt_gui_menu_popup(GtkMenu *menu, GtkWidget *button, GdkGravity widget_anchor, GdkGravity menu_anchor)
Definition popup.c:53
#define DT_PIXEL_SIMD_CHANNELS
Definition simd.h:63
const float r
char lens_key[512]
Definition lens.c:617
ls_camera_t cam
Definition lens.c:613
ls_db_t * db
Definition lens.c:609
gboolean cam_cached
Definition lens.c:615
long long lens_id
Definition lens.c:618
gboolean lens_cached
Definition lens.c:619
gboolean tried
Definition lens.c:610
gboolean cam_found
Definition lens.c:614
char cam_key[512]
Definition lens.c:612
dt_image_t image_storage
Definition develop.h:225
GList * forms
Definition develop.h:304
One module instance's contribution, as data.
Definition geometry.h:99
A module's geometry, evaluated. Pure functions of the record's own data.
Definition geometry.h:75
int32_t height
Definition image.h:397
float exif_focus_distance
Definition image.h:372
ls_vendor_data_t exif_correction
Definition image.h:469
float exif_aperture
Definition image.h:369
int32_t crop_height
Definition image.h:398
int32_t width
Definition image.h:397
float exif_focal_length
Definition image.h:371
char exif_maker[64]
Definition image.h:374
int32_t crop_y
Definition image.h:398
char exif_lens[128]
Definition image.h:376
int32_t crop_x
Definition image.h:398
int32_t p_height
Definition image.h:397
int32_t p_width
Definition image.h:397
char exif_model[64]
Definition image.h:375
int32_t crop_width
Definition image.h:398
float exif_crop
Definition image.h:373
enum dt_interpolation_type id
dt_iop_lensfun_data_t data
Definition lens.c:2251
ls_knots_t ls_knots
Definition lens.c:890
ls_lens_t ls_lens
Definition lens.c:884
gboolean ls_have
Definition lens.c:885
dt_lens_type_t target_geom
Definition lens.c:878
gboolean do_nan_checks
Definition lens.c:879
gboolean tca_override
Definition lens.c:880
gboolean knots_have
Definition lens.c:891
dt_lens_source_t axis_row[DT_LENS_AXIS_LAST][DT_LENS_SOURCE_LAST]
Definition lens.c:565
GtkMenu * camera_menu
Definition lens.c:557
int axis_rows[DT_LENS_AXIS_LAST]
Definition lens.c:566
GtkWidget * target_geom
Definition lens.c:567
GtkWidget * tca_r
Definition lens.c:567
GtkWidget * cbe[3]
Definition lens.c:555
GtkWidget * axis_source[DT_LENS_AXIS_LAST]
Definition lens.c:561
GtkWidget * lens_param_box
Definition lens.c:554
GtkWidget * reverse
Definition lens.c:567
GtkWidget * scale
Definition lens.c:567
GtkWidget * lens_model
Definition lens.c:558
GtkWidget * tca_b
Definition lens.c:567
GtkWidget * camera_model
Definition lens.c:556
gboolean tca_override
Definition lens.c:304
dt_lens_type_t target_geom
Definition lens.c:301
GtkWidget * widget
Definition imageop_gui.h:47
dt_iop_params_t * default_params
Definition imageop.h:333
struct dt_iop_module_gui_t * gui
Definition imageop.h:346
struct dt_develop_t * dev
Definition imageop.h:311
dt_iop_global_data_t * global_data
Definition imageop.h:337
dt_iop_params_t * params
Definition imageop.h:333
Region of interest passed through the pixelpipe.
Definition format.h:49
double scale
Definition format.h:51
int width
Definition format.h:50
int height
Definition format.h:50
#define __DT_CLONE_TARGETS__
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
gboolean dt_gui_widgets_suppressed(void)
#define dt_gui_widget_freeze()
#define DT_GUI_BOX_SPACING
void dtgtk_cairo_paint_refresh(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)