109#include "lensserious.h"
110#include "lensserious_db.h"
111#include "lensserious_vendor.h"
192#define DT_LENS_MODIFY_DISTORTION_PACK \
193 (DT_LENS_MODIFY_DISTORTION | DT_LENS_MODIFY_GEOMETRY | DT_LENS_MODIFY_SCALE)
196#define DT_LENS_MODIFY_ANSEL_MASK 0xFF000000u
206#define DT_LENS_MODIFY_ALL_AXES ((int)~DT_LENS_MODIFY_ANSEL_MASK)
213 "the axis space and Ansel's own bits must not overlap");
217 "every correction axis must live in the axis half");
218_Static_assert((DT_LENS_SOURCE_BITS << DT_LENS_SOURCE_SHIFT_VIGNETTING) > 0,
219 "no source field may reach the sign bit of modify_flags");
222 "the source fields must not overlap each other");
280 "projection numbering must match ls_lens_type_t: stored params depend on it");
393 const gboolean tca_override,
443 p->modify_flags &= ~_lens_axis_flags(axis);
546 default:
return FALSE;
669 const int found_version,
const char *detail)
671 const char *reason = (!
IS_NULL_PTR(detail) && detail[0]) ? detail :
"no further detail";
675 case LS_DB_OPEN_NO_FILE:
679 case LS_DB_OPEN_UNREADABLE:
685 "[lens] `%s' exists but could not be read: %s. Check its permissions, and "
686 "that it is not truncated\n", path, reason);
689 case LS_DB_OPEN_SCHEMA:
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",
699 path, found_version, ls_db_schema_required());
719 ls_db_open_status_t config_status = LS_DB_OPEN_NO_FILE;
720 int config_version = -1;
721 char config_detail[256] = { 0 };
725 tls->
db = ls_db_open_diagnostic(config_path, &config_status, &config_version, config_detail,
726 sizeof(config_detail));
728 ls_db_open_status_t data_status = LS_DB_OPEN_NO_FILE;
729 int data_version = -1;
730 char data_detail[256] = { 0 };
735 tls->
db = ls_db_open_diagnostic(path, &data_status, &data_version, data_detail,
736 sizeof(data_detail));
748 "[lens] no calibration database, so no lens correction is available.\n");
755 if(config_status != LS_DB_OPEN_OK && config_status != LS_DB_OPEN_NO_FILE)
759 (config_status == LS_DB_OPEN_OK) ? config_path : path,
760 ls_db_schema_version(tls->
db));
793 if(found) *
out = cam;
830 const char *lens_name)
832 if(
IS_NULL_PTR(lens_name) || !lens_name[0])
return -1;
838 snprintf(
key,
sizeof(
key),
"%lld\x1f%.4f\x1f%.4f\x1f%s", mount_id, (
double)crop,
839 (
double)focal, lens_name);
845 const int n = ls_db_match_lens(db, NULL, lens_name, mount_id, crop,
m,
846 (
int)(
sizeof(
m) /
sizeof(*
m)));
848 for(
int i = 0;
i <
n;
i++)
851 if(ls_db_lens_by_id(db,
m[
i].lens_id, &cand) != 1)
continue;
856 && (focal < cand.min_focal - 0.05f || focal > cand.max_focal + 0.05f))
916 return _(
"_lens correction");
921 return _(
"vignette|chromatic aberrations|distortion");
928 _(
"linear, RGB, scene-referred"),
929 _(
"geometric and reconstruction, RGB"),
930 _(
"linear, RGB, scene-referred"));
955 void *new_params,
const int new_version)
957 if(old_version == 2 && new_version == 5)
974 } dt_iop_lensfun_params_v2_t;
976 const dt_iop_lensfun_params_v2_t *
o = (dt_iop_lensfun_params_v2_t *)old_params;
982 n->modify_flags =
o->modify_flags;
983 n->inverse =
o->inverse;
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));
1001 if(old_version == 3 && new_version == 5)
1017 } dt_iop_lensfun_params_v3_t;
1019 const dt_iop_lensfun_params_v3_t *
o = (dt_iop_lensfun_params_v3_t *)old_params;
1028 memcpy(
n,
o,
sizeof(*
o));
1034 n->tca_r =
o->tca_b;
1035 n->tca_b =
o->tca_r;
1040 if(old_version == 4 && new_version == 5)
1057 } dt_iop_lensfun_params_v4_t;
1059 const dt_iop_lensfun_params_v4_t *
o = (dt_iop_lensfun_params_v4_t *)old_params;
1068 n->tca_r =
o->tca_b;
1069 n->tca_b =
o->tca_r;
1079 const char *found_or = strstr(orig_lens,
" or ");
1080 const char *found_parenthesis = strstr(orig_lens,
" (");
1082 if(found_or || found_parenthesis)
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;
1090 char *new_lens = (
char *)malloc(pos + 1);
1092 strncpy(new_lens, orig_lens, pos);
1093 new_lens[pos] =
'\0';
1099 char *new_lens = strdup(orig_lens);
1105 char *new_lens = strdup(orig_lens);
1126 int mods_filter, gboolean force_inverse, ls_modifier_t *mod,
1127 ls_modifier_t *vig_mod)
1129 memset(mod, 0,
sizeof(*mod));
1130 if(mods_done) *mods_done = 0;
1137 int mods_todo =
d->modify_flags & mods_filter;
1159 const int reverse = force_inverse ? !
d->inverse :
d->inverse;
1182 const float knots_scale =
d->knots_scale * ((
d->scale > 0.f) ?
d->scale : 1.f);
1190 int knot_want = want & ~LS_ENABLE_GEOMETRY;
1193 knot_want &= ~LS_ENABLE_TCA;
1195 got = ls_modifier_init_knots(mod, &
d->ls_knots, w, h, knots_scale, knot_want, reverse);
1217 if((want & LS_ENABLE_TCA) && !(knot_want & LS_ENABLE_TCA) &&
d->ls_have)
1219 ls_modifier_t tca_mod;
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)
1224 mod->tca = tca_mod.tca;
1225 mod->enabled |= LS_ENABLE_TCA;
1226 got |= LS_ENABLE_TCA;
1241 if((want & LS_ENABLE_GEOMETRY) &&
d->ls_have &&
d->crop > 0.f &&
d->focal > 0.f)
1243 if(ls_modifier_set_projection(mod, (
int)
d->ls_lens.type, (
int)
d->target_geom,
1245 got |= LS_ENABLE_GEOMETRY;
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);
1262 if(mod->geometry_unsupported) done &= ~DT_LENS_MODIFY_GEOMETRY;
1280 if(!vig_wanted || vig_embedded == geom_embedded)
1289 else if(vig_embedded)
1290 ls_modifier_init_knots(vig_mod, &
d->ls_knots, w, h, 1.f, LS_ENABLE_VIGNETTING, reverse);
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);
1301 if(vig_wanted && (vig_mod->enabled & LS_ENABLE_VIGNETTING))
1304 done &= ~DT_LENS_MODIFY_VIGNETTING;
1307 if(mods_done) *mods_done = done;
1315 const dt_aligned_pixel_simd_t half =
dt_simd_set1(0.5f);
1320 for(
int k = 0;
k <
ch *
width;
k++) buf[
k] = 0.5f;
1337 const void *
const ivoid,
void *
const ovoid)
1343 const int ch =
piece->dsc_in.channels;
1344 const int ch_width =
ch * roi_in->
width;
1357 const float orig_w = roi_in->
scale *
piece->buf_in.width, orig_h = roi_in->
scale *
piece->buf_in.height;
1360 ls_modifier_t modifier;
1361 ls_modifier_t vig_modifier;
1362 get_modifier(&modflags, orig_w, orig_h,
d, used_lf_mask,
FALSE, &modifier, &vig_modifier);
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,
1385 && ls_eval_from_modifier(&vig_modifier, &vp);
1393 const size_t bufsize = (size_t)roi_out->
width * 2 * 3;
1395 size_t padded_bufsize;
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)
1403 for(
int y = 0; y < roi_out->
height; y++)
1406 ls_modifier_apply_subpixel_geometry(&modifier, roi_out->
x, roi_out->
y + y, roi_out->
width, 1, bufptr);
1410 for(
int x = 0;
x < roi_out->
width;
x++, bufptr += 6,
out +=
ch)
1412 dt_aligned_pixel_simd_t pixel = { 0.f };
1413 for(
int c = 0; c < 3; c++)
1415 if(
d->do_nan_checks && (!isfinite(bufptr[c * 2]) || !isfinite(bufptr[c * 2 + 1])))
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);
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;
1435 if(raw_monochrome) pixel[0] = pixel[2] = pixel[1];
1439 if(
d->do_nan_checks && (!isfinite(bufptr[2]) || !isfinite(bufptr[3])))
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);
1457 else for(
int c = 0; c <
ch; c++)
out[c] = pixel[c];
1470 for(
int y = 0; y < roi_out->
height; y++)
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)));
1489 const size_t buf2size = (size_t)roi_out->
width * 2 * 3;
1490 size_t padded_buf2size;
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)
1499 for(
int y = 0; y < roi_out->
height; y++)
1502 ls_modifier_apply_subpixel_geometry(&modifier, roi_out->
x, roi_out->
y + y, roi_out->
width, 1, buf2ptr);
1505 for(
int x = 0;
x < roi_out->
width;
x++, buf2ptr += 6,
out +=
ch)
1507 dt_aligned_pixel_simd_t pixel = { 0.f };
1508 for(
int c = 0; c < 3; c++)
1510 if(
d->do_nan_checks && (!isfinite(buf2ptr[c * 2]) || !isfinite(buf2ptr[c * 2 + 1])))
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);
1525 pixel[c] *= ls_eval_vignette_factor(&vp, buf2ptr[c * 2], buf2ptr[c * 2 + 1]);
1527 if(raw_monochrome) pixel[0] = pixel[2] = pixel[1];
1530 if(
d->do_nan_checks && (!isfinite(buf2ptr[2]) || !isfinite(buf2ptr[3])))
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);
1548 else for(
int c = 0; c <
ch; c++)
out[c] = pixel[c];
1561 for(
int y = 0; y < roi_in->
height; 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)));
1592 ls_modifier_t modifier;
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;
1608 const float orig_w = roi_in->
scale *
piece->buf_in.width, orig_h = roi_in->
scale *
piece->buf_in.height;
1610 size_t origin[] = { 0, 0, 0 };
1611 size_t oregion[] = { (size_t)owidth, (
size_t)oheight, 1 };
1612 size_t isizes[] = { (size_t)
ROUNDUPDWD(iwidth, devid), (size_t)
ROUNDUPDHT(iheight, devid), 1 };
1613 size_t osizes[] = { (size_t)
ROUNDUPDWD(owidth, devid), (size_t)
ROUNDUPDHT(oheight, devid), 1 };
1624 if(err != CL_SUCCESS)
goto error;
1628 switch(interpolation->
id)
1644 ls_modifier_t vig_modifier;
1645 get_modifier(&modflags, orig_w, orig_h,
d, used_lf_mask,
FALSE, &modifier, &vig_modifier);
1659 have_eval = ls_eval_from_modifier(&modifier, &
p) != 0;
1670 if(ls_eval_from_modifier(&vig_modifier, &vp)) ls_eval_adopt_vignetting(&
p, &vp);
1694 if(err != CL_SUCCESS)
goto error;
1702 const int vx =
d->inverse ? roi_out_x : roi_in_x;
1703 const int vy =
d->inverse ? roi_out_y : roi_in_y;
1704 const int vw =
d->inverse ? owidth : iwidth;
1705 const int vh =
d->inverse ? oheight : iheight;
1714 d->inverse ? osizes : isizes);
1715 if(err != CL_SUCCESS)
goto error;
1720 if(err != CL_SUCCESS)
goto error;
1757 tiling->factor_cl = 2.0f;
1758 tiling->maxbuf_cl = 1.0f;
1767 float *
const __restrict points,
size_t points_count)
1772 const float orig_w =
piece->buf_in.width, orig_h =
piece->buf_in.height;
1777 ls_modifier_t modifier;
1778 get_modifier(&modflags, orig_w, orig_h,
d, used_lf_mask,
TRUE, &modifier, NULL);
1783 for(
size_t i = 0;
i < points_count * 2;
i += 2)
1786 ls_modifier_apply_subpixel_geometry(&modifier, points[
i], points[
i + 1], 1, 1, buf);
1790 points[
i + 1] = buf[3];
1799 float *
const __restrict points,
size_t points_count)
1807 const float orig_w =
piece->buf_in.width, orig_h =
piece->buf_in.height;
1809 ls_modifier_t modifier;
1816 for(
size_t i = 0;
i < points_count * 2;
i += 2)
1819 ls_modifier_apply_subpixel_geometry(&modifier, points[
i], points[
i + 1], 1, 1, buf);
1823 points[
i + 1] = buf[3];
1833 const float *
const in,
float *
const out,
const dt_iop_roi_t *
const roi_in,
1845 const float orig_w = roi_in->
scale *
piece->buf_in.width, orig_h = roi_in->
scale *
piece->buf_in.height;
1847 ls_modifier_t modifier;
1851 FALSE, &modifier, NULL);
1862 const size_t bufsize = (size_t)roi_out->
width * 2 * 3;
1863 size_t padded_bufsize;
1867 for(
int y = 0; y < roi_out->
height; y++)
1870 ls_modifier_apply_subpixel_geometry(&modifier, roi_out->
x, roi_out->
y + y, roi_out->
width, 1, bufptr);
1873 float *_out =
out + (size_t)y * roi_out->
width;
1874 for(
int x = 0;
x < roi_out->
width;
x++, bufptr += 6, _out++)
1876 if(
d->do_nan_checks && (!isfinite(bufptr[2]) || !isfinite(bufptr[3])))
1883 const float pi0 = bufptr[2] - roi_in->
x;
1884 const float pi1 = bufptr[3] - roi_in->
y;
1911 const float orig_w = roi_in->
scale *
piece->buf_in.width;
1912 const float orig_h = roi_in->
scale *
piece->buf_in.height;
1914 ls_modifier_t modifier;
1919 const int xoff = roi_in->
x;
1920 const int yoff = roi_in->
y;
1923 const int awidth = abs(
width);
1924 const int aheight = abs(
height);
1925 const int xstep = (
width < 0) ? -1 : 1;
1926 const int ystep = (
height < 0) ? -1 : 1;
1928 float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX;
1929 const size_t nbpoints = 2 * awidth + 2 * aheight;
1938#pragma omp parallel default(none) reduction(min : xm, ym) reduction(max : xM, yM) \
1939 firstprivate(modifier, xoff, yoff, awidth, aheight, width, height, nbpoints, ystep, xstep, buf)
1943 for(
int i = 0;
i < awidth;
i++)
1944 ls_modifier_apply_subpixel_geometry(&modifier, xoff +
i * xstep, yoff, 1, 1, buf + 6 *
i);
1946 for(
int i = 0;
i < awidth;
i++)
1947 ls_modifier_apply_subpixel_geometry(&modifier, xoff +
i * xstep, yoff + (
height - 1), 1, 1, buf + 6 * (awidth +
i));
1949 for(
int j = 0; j < aheight; j++)
1950 ls_modifier_apply_subpixel_geometry(&modifier, xoff, yoff + j * ystep, 1, 1, buf + 6 * (2 * awidth + j));
1952 for(
int j = 0; j < aheight; j++)
1953 ls_modifier_apply_subpixel_geometry(&modifier, xoff + (
width - 1), yoff + j * ystep, 1, 1, buf + 6 * (2 * awidth + aheight + j));
1959 for(
size_t k = 0;
k < nbpoints;
k++)
1962 for(
size_t c = 0; c < 6; c+=2)
1964 const float x = buf[6 *
k + c];
1965 const float y = buf[6 *
k + c + 1];
1966 xm = isnan(
x) ? xm :
MIN(xm,
x);
1967 xM = isnan(
x) ? xM :
MAX(xM,
x);
1968 ym = isnan(y) ? ym :
MIN(ym, y);
1969 yM = isnan(y) ? yM :
MAX(yM, y);
1977 if(!isfinite(xm) || !(0 <= xm && xm < orig_w)) xm = 0;
1978 if(!isfinite(xM) || !(1 <= xM && xM < orig_w)) xM = orig_w;
1979 if(!isfinite(ym) || !(0 <= ym && ym < orig_h)) ym = 0;
1980 if(!isfinite(yM) || !(1 <= yM && yM < orig_h)) yM = orig_h;
1983 roi_in->
x = fmaxf(0.0f, roundf(xm - interpolation->
width));
1984 roi_in->
y = fmaxf(0.0f, roundf(ym - interpolation->
width));
1985 roi_in->
width = roundf(fminf(orig_w - roi_in->
x, xM - roi_in->
x + interpolation->
width));
1986 roi_in->
height = roundf(fminf(orig_h - roi_in->
y, yM - roi_in->
y + interpolation->
width));
1989 roi_in->
x = CLAMP(roi_in->
x, 0, (
int)floorf(orig_w));
1990 roi_in->
y = CLAMP(roi_in->
y, 0, (
int)floorf(orig_h));
1991 roi_in->
width = CLAMP(roi_in->
width, 1, (
int)ceilf(orig_w) - roi_in->
x);
1992 roi_in->
height = CLAMP(roi_in->
height, 1, (
int)ceilf(orig_h) - roi_in->
y);
2043 memset(&
d->ls_lens, 0,
sizeof(
d->ls_lens));
2052 long long mount_id = 0;
2053 float camera_crop = 0.f;
2068 d->crop = camera.crop_factor;
2069 camera_crop = camera.crop_factor;
2070 mount_id = camera.mount_id;
2087 if(
p->lens[0] && mount_id > 0)
2089 const long long lens_id =
_ls_find_lens(mount_id, camera_crop,
p->focal,
p->lens);
2091 if(lens_id >= 0 && !
IS_NULL_PTR(db) && ls_db_lens_by_id(db, lens_id, &
d->ls_lens) == 1)
2103 "[lens] `%s' is not a camera this database knows, so `%s' cannot be resolved to"
2104 " one lens; correcting from the database is declined\n",
p->camera,
p->lens);
2130 d->ls_lens.type = LS_LENS_RECTILINEAR;
2131 d->ls_lens.crop_factor =
d->crop;
2132 d->ls_lens.min_focal =
p->focal;
2133 d->ls_lens.max_focal =
p->focal;
2141 d->ls_lens.n_tca = 1;
2142 d->ls_lens.tca[0].model = LS_TCA_LINEAR;
2143 d->ls_lens.tca[0].focal =
p->focal;
2144 d->ls_lens.tca[0].terms[0] =
p->tca_r;
2145 d->ls_lens.tca[0].terms[1] =
p->tca_b;
2146 for(
int i = 2;
i < 6;
i++)
d->ls_lens.tca[0].terms[
i] = 0.f;
2149 d->modify_flags =
p->modify_flags;
2151 d->inverse =
p->inverse;
2152 d->scale =
p->scale;
2153 d->focal =
p->focal;
2154 d->aperture =
p->aperture;
2155 d->distance =
p->distance;
2156 d->target_geom =
p->target_geom;
2157 d->do_nan_checks =
TRUE;
2158 d->tca_override =
p->tca_override;
2171 d->knots_scale = 1.f;
2173 gboolean wants_embedded =
FALSE;
2191 "[lens] an axis asks for the vendor profile but this file carries none;"
2192 " correcting from the community profile instead\n");
2195 "[lens] this file's vendor profile could not be decoded;"
2196 " correcting from the community profile instead\n");
2199 d->knots_scale = (scale > 0.f) ? scale : 1.f;
2200 d->knots_have =
TRUE;
2211 d->do_nan_checks =
FALSE;
2213 else if((
int)
d->target_geom == (
int)
d->ls_lens.type)
2215 d->do_nan_checks =
FALSE;
2267 float *points,
size_t points_count, gboolean inverse)
2276 ls_modifier_t modifier;
2283 for(
size_t i = 0;
i < points_count * 2;
i += 2)
2286 ls_modifier_apply_subpixel_geometry(&modifier, points[
i], points[
i + 1], 1, 1, buf);
2290 points[
i + 1] = buf[3];
2350 const int program = 2;
2369 const dt_image_t *img = &
module->dev->image_storage;
2376 g_strlcpy(
d->lens, new_lens,
sizeof(
d->lens));
2378 g_strlcpy(
d->camera, img->
exif_model,
sizeof(
d->camera));
2412 d->modify_flags &= ~DT_LENS_MODIFY_TCA;
2417 for(
char cnt = 0, *c =
model; c <
model + 100 && *c !=
'\0'; c++)
2419 if(++cnt == 2) *c =
'\0';
2428 char mount[128] = { 0 };
2431 ls_db_mount_name(db, cam.mount_id, mount,
sizeof(mount));
2432 const gboolean fixed_lens = (mount[0] !=
'\0') && islower((
unsigned char)mount[0]);
2434 long long lens_id =
_ls_find_lens(cam.mount_id, cam.crop_factor,
d->focal,
d->lens);
2436 if(lens_id < 0 && fixed_lens)
2441 g_strlcpy(
d->lens,
"",
sizeof(
d->lens));
2443 const int n = ls_db_lenses_for_mount(db, cam.mount_id, NULL, 0);
2446 long long *ids = (
long long *)
dt_alloc_align(
sizeof(
long long) * (size_t)
n);
2449 ls_db_lenses_for_mount(db, cam.mount_id, ids,
n);
2452 size_t shortest = SIZE_MAX;
2453 for(
int i = 0;
i <
n;
i++)
2455 char maker[128] =
"", lmodel[256] =
"";
2456 if(ls_db_lens_name(db, ids[
i],
maker,
sizeof(
maker), lmodel,
sizeof(lmodel)) <= 0)
2458 const size_t len = strlen(lmodel);
2463 g_strlcpy(
d->lens, lmodel,
sizeof(
d->lens));
2474 if(ls_db_lens_by_id(db, lens_id, &lens) == 1)
2478 d->crop = cam.crop_factor;
2480 module->workflow_enabled = dt_image_needs_rawprepare(img);
2511 if(
x == 0)
return 1;
2533 int length = array->len;
2534 g_ptr_array_set_size(array, length + 1);
2535 const void **root = (
const void **)array->pdata;
2537 int m = 0, l = 0,
r = length - 1;
2540 if(l <=
r && !root[
r])
r--;
2545 int cmp = compare(root[
m], item);
2560 memmove(root +
m + 1, root +
m,
sizeof(
void *) * (length -
m));
2567 int length = array->len;
2568 void **root = array->pdata;
2570 int l = 0,
r = length - 1;
2573 if(!length)
return -1;
2581 cmp = compare(root[
m], item);
2597 int length = array->len;
2598 g_ptr_array_set_size(array, length + 1);
2599 root = (
const void **)array->pdata;
2600 memmove(root + index + 1, root + index,
sizeof(
void *) * (length - index));
2623 char maker[128] =
"",
model[256] =
"", variant[128] =
"";
2627 variant,
sizeof(variant)) != 1
2628 || ls_db_camera_by_id(db, camera_id, &cam) != 1)
2631 g_strlcpy(
p->camera,
model,
sizeof(
p->camera));
2632 p->crop = cam.crop_factor;
2648 char maker[128] =
"",
model[256] =
"", variant[128] =
"";
2652 variant,
sizeof(variant)) != 1
2653 || ls_db_camera_by_id(db, camera_id, &cam) != 1)
2655 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
g->camera_model))),
"");
2656 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->camera_model),
"");
2661 g->camera_id = camera_id;
2664 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
g->camera_model))), fm);
2670 char _variant[
sizeof(variant) + 4];
2672 snprintf(_variant,
sizeof(_variant),
" (%s)", variant);
2676 char mount[128] =
"";
2677 ls_db_mount_name(db, cam.mount_id, mount,
sizeof(mount));
2679 fm = g_strdup_printf(_(
"maker:\t\t%s\n"
2682 "crop factor:\t%.1f"),
2683 maker,
model, _variant, mount, cam.crop_factor);
2684 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->camera_model), fm);
2696 const long long camera_id =
2697 (
long long)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem),
"lens-camera-id"));
2726 GPtrArray *makers, *submenus;
2730 gtk_widget_destroy(GTK_WIDGET(
g->camera_menu));
2731 g->camera_menu = NULL;
2739 submenus = g_ptr_array_new();
2740 for(
int i = 0;
i <
n;
i++)
2742 char maker[128] =
"",
model[256] =
"", variant[128] =
"";
2744 variant,
sizeof(variant)) != 1)
2755 submenu = gtk_menu_new();
2759 submenu = (
GtkWidget *)g_ptr_array_index(submenus, idx);
2762 item = gtk_menu_item_new_with_label(
model);
2765 gchar *fm = g_strdup_printf(
"%s (%s)",
model, variant);
2766 item = gtk_menu_item_new_with_label(fm);
2769 gtk_widget_show(item);
2770 g_object_set_data(G_OBJECT(item),
"lens-camera-id", GINT_TO_POINTER((gint)ids[
i]));
2772 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
2775 g->camera_menu = GTK_MENU(gtk_menu_new());
2776 for(
unsigned i = 0;
i < makers->len;
i++)
2778 GtkWidget *item = (
GtkWidget *)gtk_menu_item_new_with_label((
const gchar *)g_ptr_array_index(makers,
i));
2779 gtk_widget_show(item);
2780 gtk_menu_shell_append(GTK_MENU_SHELL(
g->camera_menu), item);
2781 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), (
GtkWidget *)g_ptr_array_index(submenus,
i));
2784 g_ptr_array_free(submenus,
TRUE);
2785 g_ptr_array_free(makers,
TRUE);
2794 const int n = ls_db_list_cameras(db, NULL, 0);
2795 if(
n <= 0)
return NULL;
2796 long long *ids = (
long long *)
dt_alloc_align(
sizeof(
long long) * (size_t)
n);
2798 *out_n = ls_db_list_cameras(db, ids,
n);
2804 while(txt[0] && isspace(txt[0])) txt++;
2805 size_t len = strlen(txt);
2806 if(len > sz_model - 1) len = sz_model - 1;
2807 memcpy(
model, txt, len);
2824 dt_gui_menu_popup(GTK_MENU(
g->camera_menu), button, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH);
2834 if(text) (
void)sscanf(text,
"%f", &
p->focal);
2843 if(text) (
void)sscanf(text,
"%f", &
p->aperture);
2852 if(text) (
void)sscanf(text,
"%f", &
p->distance);
2860 gtk_widget_destroy(widget);
2876 default:
return _(
"unknown");
2892 char l_maker[128] =
"", l_model[256] =
"";
2894 || ls_db_lens_name(db, lens_id, l_maker,
sizeof(l_maker), l_model,
sizeof(l_model)) <= 0)
2897 g_strlcpy(
p->lens, l_model,
sizeof(
p->lens));
2913 gdouble focal_values[]
2914 = { -INFINITY, 4.5, 8, 10, 12, 14, 15, 16, 17, 18, 20, 24, 28, 30, 31, 35,
2915 38, 40, 43, 45, 50, 55, 60, 70, 75, 77, 80, 85, 90, 100, 105, 110,
2916 120, 135, 150, 200, 210, 240, 250, 300, 400, 500, 600, 800, 1000, INFINITY };
2917 gdouble aperture_values[]
2918 = { -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,
2919 5.6, 6.3, 7.1, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 29, 32, 38, INFINITY };
2923 char l_maker[128] =
"", l_model[256] =
"";
2924 float min_focal = 0.f, max_focal = 0.f, min_ap = 0.f, max_ap = 0.f;
2925 const gboolean have = (lens_id >= 0) && !
IS_NULL_PTR(db)
2926 && (ls_db_lens_by_id(db, lens_id, &lens_v) == 1)
2927 && (ls_db_lens_name(db, lens_id, l_maker,
sizeof(l_maker),
2928 l_model,
sizeof(l_model)) > 0);
2929 if(have) ls_db_lens_range(db, lens_id, &min_focal, &max_focal, &min_ap, &max_ap);
2948 maker = l_maker[0] ? l_maker : NULL;
2949 model = l_model[0] ? l_model : NULL;
2954 fm = g_strdup_printf(
"%s, %s",
maker,
model);
2956 fm = g_strdup_printf(
"%s",
model);
2957 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
g->lens_model))), fm);
2961 char focal[100], aperture[100], mounts[200];
2963 if(min_focal < max_focal)
2964 snprintf(focal,
sizeof(focal),
"%g-%gmm", min_focal, max_focal);
2966 snprintf(focal,
sizeof(focal),
"%gmm", min_focal);
2968 snprintf(aperture,
sizeof(aperture),
"%g-%g", min_ap, max_ap);
2970 snprintf(aperture,
sizeof(aperture),
"%g", min_ap);
2973 ls_db_lens_mounts(db, lens_id, mounts,
sizeof(mounts));
2975 fm = g_strdup_printf(_(
"maker:\t\t%s\n"
2977 "focal range:\t%s\n"
2979 "crop factor:\t%.1f\n"
2985 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->lens_model), fm);
2989 gtk_container_foreach(GTK_CONTAINER(
g->lens_param_box),
delete_children, NULL);
2991 int ffi = 1, fli = -1;
2992 for(
i = 1;
i <
sizeof(focal_values) /
sizeof(gdouble) - 1;
i++)
2994 if(focal_values[
i] < min_focal) ffi =
i + 1;
2995 if(focal_values[
i] > max_focal && fli == -1) fli =
i;
2997 if(focal_values[ffi] > min_focal)
2999 focal_values[ffi - 1] = min_focal;
3002 if(max_focal == 0 || fli < 0) fli =
sizeof(focal_values) /
sizeof(gdouble) - 2;
3003 if(focal_values[fli + 1] < max_focal)
3005 focal_values[fli + 1] = max_focal;
3008 if(fli < ffi) fli = ffi + 1;
3016 gtk_widget_set_tooltip_text(w, _(
"focal length (mm)"));
3017 snprintf(txt,
sizeof(txt),
"%.*f",
precision(
p->focal, 10.0),
p->focal);
3019 for(
int k = 0;
k < fli - ffi;
k++)
3021 snprintf(txt,
sizeof(txt),
"%.*f",
precision(focal_values[ffi +
k], 10.0), focal_values[ffi +
k]);
3025 gtk_box_pack_start(GTK_BOX(
g->lens_param_box), w,
TRUE,
TRUE, 0);
3030 ffi = 1, fli =
sizeof(aperture_values) /
sizeof(gdouble) - 1;
3031 for(
i = 1;
i <
sizeof(aperture_values) /
sizeof(gdouble) - 1;
i++)
3032 if(aperture_values[
i] < min_ap) ffi =
i + 1;
3033 if(aperture_values[ffi] > min_ap)
3035 aperture_values[ffi - 1] = min_ap;
3041 gtk_widget_set_tooltip_text(w, _(
"f-number (aperture)"));
3042 snprintf(txt,
sizeof(txt),
"%.*f",
precision(
p->aperture, 10.0),
p->aperture);
3044 for(
int k = 0;
k < fli - ffi;
k++)
3046 snprintf(txt,
sizeof(txt),
"%.*f",
precision(aperture_values[ffi +
k], 10.0), aperture_values[ffi +
k]);
3050 gtk_box_pack_start(GTK_BOX(
g->lens_param_box), w,
TRUE,
TRUE, 0);
3056 gtk_widget_set_tooltip_text(w, _(
"distance to subject"));
3057 snprintf(txt,
sizeof(txt),
"%.*f",
precision(
p->distance, 10.0),
p->distance);
3060 for(
int k = 0;
k < 25;
k++)
3062 if(val > 1000.0f) val = 1000.0f;
3063 snprintf(txt,
sizeof(txt),
"%.*f",
precision(val, 10.0), val);
3065 if(val >= 1000.0f)
break;
3069 gtk_box_pack_start(GTK_BOX(
g->lens_param_box), w,
TRUE,
TRUE, 0);
3073 gtk_widget_show_all(
g->lens_param_box);
3089 const long long lens_id =
3090 (
long long)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem),
"lens-id"));
3113 GPtrArray *makers, *submenus;
3117 gtk_widget_destroy(GTK_WIDGET(
g->lens_menu));
3118 g->lens_menu = NULL;
3126 submenus = g_ptr_array_new();
3127 for(
int i = 0;
i <
n;
i++)
3140 submenu = gtk_menu_new();
3144 submenu = (
GtkWidget *)g_ptr_array_index(submenus, idx);
3146 item = gtk_menu_item_new_with_label(
model);
3147 gtk_widget_show(item);
3148 g_object_set_data(G_OBJECT(item),
"lens-id", GINT_TO_POINTER((gint)ids[
i]));
3149 g_signal_connect(G_OBJECT(item),
"activate", G_CALLBACK(
lens_menu_select), self);
3150 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
3153 g->lens_menu = GTK_MENU(gtk_menu_new());
3154 for(
unsigned i = 0;
i < makers->len;
i++)
3156 GtkWidget *item = gtk_menu_item_new_with_label((
const gchar *)g_ptr_array_index(makers,
i));
3157 gtk_widget_show(item);
3158 gtk_menu_shell_append(GTK_MENU_SHELL(
g->lens_menu), item);
3159 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), (
GtkWidget *)g_ptr_array_index(submenus,
i));
3162 g_ptr_array_free(submenus,
TRUE);
3163 g_ptr_array_free(makers,
TRUE);
3185 const gboolean have_cam = (
g->camera_id >= 0) && (ls_db_camera_by_id(db,
g->camera_id, &cam) == 1);
3189 enum { MAX_HITS = 32 };
3190 ls_db_match_t
m[MAX_HITS];
3191 const int n = ls_db_match_lens(db, NULL,
model, have_cam ? cam.mount_id : 0,
3192 have_cam ? cam.crop_factor : 0.f,
m, MAX_HITS);
3193 if(
n <= 0)
return NULL;
3194 long long *ids = (
long long *)
dt_alloc_align(
sizeof(
long long) * (size_t)
n);
3196 for(
int i = 0;
i <
n;
i++) ids[
i] =
m[
i].lens_id;
3203 const int total = ls_db_list_lenses(db, NULL, 0);
3204 if(total <= 0)
return NULL;
3205 long long *all = (
long long *)
dt_alloc_align(
sizeof(
long long) * (size_t)total);
3207 const int got = ls_db_list_lenses(db, all, total);
3216 for(
int i = 0;
i < got;
i++)
3217 if(ls_db_lens_fits_mount(db, all[
i], cam.mount_id) == 1) all[keep++] = all[
i];
3234 dt_gui_menu_popup(GTK_MENU(
g->lens_menu), button, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH);
3328 gtk_widget_set_visible(
g->reverse,
p->inverse != 0);
3375 for(
int i = 0;
i <
g->axis_rows[axis];
i++)
3376 if(
g->axis_row[axis][
i] == source)
return i;
3447 default: have =
FALSE;
break;
3453 g->axis_row[axis][
n++] = src;
3455 g->axis_rows[axis] =
n;
3479 if(
g->axis_source[axis] == w)
return axis;
3496 if(row < 0 || row >=
g->axis_rows[axis])
return;
3523 g->axis_source[axis] = w;
3525 gtk_widget_set_tooltip_text(w, _(
tooltip));
3529 g->axis_rows[axis] = 0;
3530 g_signal_connect(G_OBJECT(w),
"value-changed",
3563 memset(&
d, 0,
sizeof(
d));
3577 ls_modifier_t modifier;
3579 scale = ls_modifier_autoscale(&modifier);
3616 memset(&
d, 0,
sizeof(
d));
3645 g->camera_menu = NULL;
3646 g->lens_menu = NULL;
3650 gtk_widget_set_name(self->
gui->
widget,
"lens-module");
3693 N_(
"correct the lens's light falloff, and where to take it from"));
3697 N_(
"correct the lens's geometric distortion, and where to take it from"));
3702 gtk_widget_set_tooltip_text(
g->target_geom, _(
"target geometry"));
3721 g_signal_connect(G_OBJECT(
g->scale),
"quad-pressed", G_CALLBACK(
autoscale_pressed), self);
3722 gtk_widget_set_tooltip_text(
g->scale, _(
"auto scale"));
3726 N_(
"correct lateral chromatic aberration, and where to take it from"));
3736 gtk_widget_set_tooltip_text(
g->tca_r, _(
"Transversal Chromatic Aberration red"));
3740 gtk_widget_set_tooltip_text(
g->tca_b, _(
"Transversal Chromatic Aberration blue"));
3747 gtk_widget_set_tooltip_text(
g->reverse, _(
"correct distortions or apply them"));
3768 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
g->camera_model))),
p->camera);
3769 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
g->lens_model))),
p->lens);
3770 gtk_widget_set_tooltip_text(
g->camera_model,
"");
3771 gtk_widget_set_tooltip_text(
g->lens_model,
"");
3795 if(
g->camera_id >= 0 &&
p->lens[0])
static double dist(double x1, double y1, double x2, double y2)
static void error(char *msg)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
void dt_bauhaus_combobox_clear(GtkWidget *widget)
void dt_bauhaus_combobox_set_editable(GtkWidget *widget, int editable)
int dt_bauhaus_combobox_get(GtkWidget *widget)
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
void dt_bauhaus_widget_set_quad_paint(GtkWidget *widget, dt_bauhaus_quad_paint_f f, int paint_flags, void *paint_data)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
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)))
gboolean dt_image_is_monochrome(const dt_image_t *img)
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
#define dt_dev_add_history_item(dev, module, enable, redraw)
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.
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
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.
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)
void dt_iop_compute_module_hash(dt_iop_module_t *module, GList *masks)
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)
@ IOP_FLAGS_TILING_FULL_ROI
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)
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...
#define IOP_GUI_ALLOC(module)
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
static const dt_dev_pixelpipe_t * pipe
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t * piece
static const dt_iop_drawlayer_params_t * params
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)
#define DT_LENS_MODIFY_ANSEL_MASK
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)
static const char *const _lens_source_names[DT_LENS_SOURCE_LAST]
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)
static long long * _camera_all_ids(int *out_n)
Every camera in the database, as ids the caller must free with dt_free_align().
const char ** description(struct dt_iop_module_t *self)
static void _lens_rebuild_axis_rows(dt_iop_module_t *self)
Every axis, for a fresh image.
static const char * _lens_type_name(int type)
A projection's name, replacing lfLens::GetLensTypeDesc().
static void _lens_fill_vignette_row(float *const buf, const int width, const int ch)
static int _lens_used_mask(dt_iop_module_t *self)
The lensfun modify mask this image allows: monochrome sensors get no TCA correction.
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.
static int ptr_array_find_sorted(const GPtrArray *array, const void *item, GCompareFunc compare)
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?
static int _lens_mask_for_mono(const gboolean monochrome)
Which axes may be attempted on this image.
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.
static void _lens_free_data(void *ptr)
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.
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.
void reload_defaults(dt_iop_module_t *module)
static int _lens_axis_presence_bit(const dt_lens_axis_t axis)
The single bit that says whether an axis is on.
static int _lens_axis_shift(const dt_lens_axis_t axis)
How far up modify_flags this axis's two source bits sit.
dt_lens_modify_t
What modify_flags holds, bit by bit.
@ DT_LENS_MODIFY_GEOMETRY
@ DT_LENS_MODIFY_VIGNETTING
@ DT_LENS_SOURCE_SHIFT_VIGNETTING
@ DT_LENS_MODIFY_DISTORTION
@ DT_LENS_SOURCE_SHIFT_TCA
@ DT_LENS_SOURCE_SHIFT_DISTORTION
dt_lens_source_t
Where one axis takes its correction from. The same vocabulary for all three.
@ DT_LENS_SOURCE_EMBEDDED
static void lens_comboentry_distance_update(GtkWidget *widget, dt_iop_module_t *self)
static char * _lens_sanitize(const char *orig_lens)
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)
static const dt_lens_source_t _lens_axis_sources[DT_LENS_AXIS_LAST][DT_LENS_SOURCE_LAST]
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.
static gboolean _lens_flags_move_pixels(const int modify_flags)
Does this flag word describe anything that MOVES pixels?
static void autoscale_pressed(GtkWidget *button, gpointer user_data)
__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)
static ls_db_t * _ls_db(void)
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.
static void camera_menu_select(GtkMenuItem *menuitem, gpointer user_data)
static const dt_geometry_vtable_t _lens_geometry_vtable
static gboolean _ls_find_camera(const char *maker, const char *model, ls_camera_t *out)
The camera an EXIF maker/model names.
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.
static void lens_comboentry_focal_update(GtkWidget *widget, dt_iop_module_t *self)
static void camera_menusearch_clicked(GtkWidget *button, gpointer user_data)
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?
static void lens_comboentry_aperture_update(GtkWidget *widget, dt_iop_module_t *self)
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.
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.
static void _lens_axis_source_changed(GtkWidget *widget, gpointer user_data)
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?
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
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.
dt_lens_axis_t
The correction axes, as an index rather than a bit – so a caller can loop.
@ DT_LENS_AXIS_DISTORTION
@ DT_LENS_AXIS_VIGNETTING
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)
static gboolean _lens_source_applicable(const dt_lens_axis_t axis, const dt_lens_source_t source)
Whether source means anything on axis.
static void ptr_array_insert_index(GPtrArray *array, const void *item, int index)
gboolean geometry_record(dt_iop_module_t *self, const void *params, dt_geometry_record_t *record)
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
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...
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?
static int precision(double x, double adj)
void gui_init(struct dt_iop_module_t *self)
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.
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
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.
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.
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)
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.
static void _lens_gui_update_sensitivity(dt_iop_module_t *self)
void cleanup_global(dt_iop_module_so_t *module)
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)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
static void lens_menu_fill(dt_iop_module_t *self, const long long *ids, int n)
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.
static void lens_menusearch_clicked(GtkWidget *button, gpointer user_data)
static float get_autoscale(dt_iop_module_t *self, dt_iop_lensfun_params_t *p)
static GPrivate _ls_tls_key
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)
void gui_cleanup(struct dt_iop_module_t *self)
@ DT_LENS_FISHEYE_EQUISOLID
@ DT_LENS_FISHEYE_ORTHOGRAPHIC
@ DT_LENS_FISHEYE_STEREOGRAPHIC
@ DT_LENS_EQUIRECTANGULAR
static int ptr_array_insert_sorted(GPtrArray *array, const void *item, GCompareFunc compare)
static void lens_menu_select(GtkMenuItem *menuitem, gpointer user_data)
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.
static gboolean _lens_data_available(const dt_iop_lensfun_data_t *d)
Does this pipe data hold ANY resolvable correction source?
static void target_geometry_changed(GtkWidget *widget, gpointer user_data)
static void parse_model(const char *txt, char *model, size_t sz_model)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
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.
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.
static void camera_set(dt_iop_module_t *self, long long camera_id)
Show a camera in the panel. VIEW ONLY – writes no parameter.
static void delete_children(GtkWidget *widget, gpointer data)
static void _ls_tls_free(gpointer data)
void init_global(dt_iop_module_so_t *module)
#define DT_LENS_MODIFY_ALL_AXES
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?
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.
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)
#define DT_LENS_MODIFY_DISTORTION_PACK
The three lensfun axes that always move together, as one flag.
static _ls_tls_t * _ls_tls_get(void)
This thread's cache block, allocated on first use. NULL only if that allocation failed,...
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)
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.
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
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.
_lib_location_type_t type
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...
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
dt_imageio_retval_t status
#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)
int dt_opencl_create_kernel(const int prog, const char *name)
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)
void dt_opencl_free_kernel(const int kernel)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
#define __OMP_PARALLEL_FOR__(...)
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
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...
#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)
#define DT_PIXEL_SIMD_CHANNELS
One module instance's contribution, as data.
const dt_geometry_vtable_t * vtable
void(* free_data)(void *data)
A module's geometry, evaluated. Pure functions of the record's own data.
float exif_focus_distance
ls_vendor_data_t exif_correction
enum dt_interpolation_type id
dt_iop_lensfun_data_t data
dt_lens_type_t target_geom
int kernel_lens_distort_bicubic
int kernel_lens_distort_bilinear
int kernel_lens_distort_mitchell
dt_lens_source_t axis_row[DT_LENS_AXIS_LAST][DT_LENS_SOURCE_LAST]
int axis_rows[DT_LENS_AXIS_LAST]
GtkWidget * axis_source[DT_LENS_AXIS_LAST]
GtkWidget * lens_param_box
dt_lens_type_t target_geom
dt_iop_global_data_t * data
dt_iop_params_t * default_params
struct dt_iop_module_gui_t * gui
struct dt_develop_t * dev
dt_iop_global_data_t * global_data
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__