100#include <gdk/gdkkeysyms.h>
167 void *new_params,
const int new_version)
169 if(new_version <= old_version)
return 1;
170 if(new_version != 5)
return 1;
173 if(old_version == 2 && new_version == 5)
180 typedef struct old_params_t
182 float angle, cx, cy, cw,
ch, k_h, k_v;
185 const old_params_t *o = (old_params_t *)old_params;
189 if(
k.u & 0x40000000u)
205 n->angle = o->angle,
n->cx = o->cx,
n->cy = o->cy,
n->cw = o->cw,
n->ch = o->ch;
206 n->kxa =
n->kxd = 0.2f;
207 n->kxc =
n->kxb = 0.8f;
208 n->kya =
n->kyb = 0.2f;
209 n->kyc =
n->kyd = 0.8f;
210 if(
n->k_h == 0 &&
n->k_v == 0)
220 n->ratio_d =
n->ratio_n = -2;
222 if(old_version == 3 && new_version == 5)
225 typedef struct old_params_t
227 float angle, cx, cy, cw,
ch, k_h, k_v;
230 const old_params_t *o = (old_params_t *)old_params;
232 n->angle = o->angle,
n->cx = o->cx,
n->cy = o->cy,
n->cw = o->cw,
n->ch = o->ch;
233 n->k_h = o->k_h,
n->k_v = o->k_v;
234 n->kxa =
n->kxd = 0.2f;
235 n->kxc =
n->kxb = 0.8f;
236 n->kya =
n->kyb = 0.2f;
237 n->kyc =
n->kyd = 0.8f;
238 if(
n->k_h == 0 &&
n->k_v == 0)
248 n->ratio_d =
n->ratio_n = -2;
250 if(old_version == 4 && new_version == 5)
252 typedef struct old_params_t
254 float angle, cx, cy, cw,
ch, k_h, k_v;
255 float kxa, kya, kxb, kyb, kxc, kyc, kxd, kyd;
257 int k_apply, crop_auto;
260 const old_params_t *o = (old_params_t *)old_params;
262 n->angle = o->angle,
n->cx = o->cx,
n->cy = o->cy,
n->cw = o->cw,
n->ch = o->ch;
263 n->k_h = o->k_h,
n->k_v = o->k_v;
264 n->kxa = o->kxa,
n->kxb = o->kxb,
n->kxc = o->kxc,
n->kxd = o->kxd;
265 n->kya = o->kya,
n->kyb = o->kyb,
n->kyc = o->kyc,
n->kyd = o->kyd;
266 n->k_type = o->k_type;
268 n->k_apply = o->k_apply;
269 n->crop_auto = o->crop_auto;
273 n->ratio_d =
n->ratio_n = -2;
343 for(
int k = 0;
k < 2;
k++)
p[
k] = aabb[2 * ((
i >>
k) & 1) +
k];
348 aabb[0] = fminf(aabb[0],
p[0]);
349 aabb[1] = fminf(aabb[1],
p[1]);
350 aabb[2] = fmaxf(aabb[2],
p[0]);
351 aabb[3] = fmaxf(aabb[3],
p[1]);
356 return _(
"this module is deprecated. please use the crop, orientation and/or rotate and perspective modules instead.");
361 return _(
"crop and rotate");
366 return _(
"reframe|perspective|keystone|distortion");
372 _(
"corrective or creative"),
373 _(
"linear, RGB, scene-referred"),
375 _(
"linear, RGB, scene-referred"));
411 float kyb,
float kyc,
float kyd,
float *a,
float *b,
float *
d,
float *e,
414 *a = -((kxb * (kyd * kyd - kyc * kyd) - kxc * kyd * kyd + kyb * (kxc * kyd - kxd * kyd) + kxd * kyc * kyd)
416 / (kxb * (kxc * kyd * kyd - kxd * kyc * kyd) + kyb * (kxd * kxd * kyc - kxc * kxd * kyd));
417 *b = ((kxb * (kxd * kyd - kxd * kyc) - kxc * kxd * kyd + kxd * kxd * kyc + (kxc * kxd - kxd * kxd) * kyb)
419 / (kxb * (kxc * kyd * kyd - kxd * kyc * kyd) + kyb * (kxd * kxd * kyc - kxc * kxd * kyd));
420 *
d = (kyb * (kxb * (kyd * k_space[3] - kyc * k_space[3]) - kxc * kyd * k_space[3] + kxd * kyc * k_space[3])
421 + kyb * kyb * (kxc * k_space[3] - kxd * k_space[3]))
422 / (kxb * kyb * (-kxc * kyd - kxd * kyc) + kxb * kxb * kyc * kyd + kxc * kxd * kyb * kyb);
423 *e = -(kxb * (kxd * kyc * k_space[3] - kxc * kyd * k_space[3])
424 + kxb * kxb * (kyd * k_space[3] - kyc * k_space[3])
425 + kxb * kyb * (kxc * k_space[3] - kxd * k_space[3]))
426 / (kxb * kyb * (-kxc * kyd - kxd * kyc) + kxb * kxb * kyc * kyd + kxc * kxd * kyb * kyb);
427 *
g = -(kyb * (kxb * (2.0f * kxc * kyd * kyd - 2.0f * kxc * kyc * kyd) - kxc * kxc * kyd * kyd
428 + 2.0f * kxc * kxd * kyc * kyd - kxd * kxd * kyc * kyc)
429 + kxb * kxb * (kyc * kyc * kyd - kyc * kyd * kyd)
430 + kyb * kyb * (-2.0f * kxc * kxd * kyd + kxc * kxc * kyd + kxd * kxd * kyc))
431 / (kxb * kxb * (kxd * kyc * kyc * kyd - kxc * kyc * kyd * kyd)
432 + kxb * kyb * (kxc * kxc * kyd * kyd - kxd * kxd * kyc * kyc)
433 + kyb * kyb * (kxc * kxd * kxd * kyc - kxc * kxc * kxd * kyd));
434 *h = (kxb * (-kxc * kxc * kyd * kyd + 2.0f * kxc * kxd * kyc * kyd - kxd * kxd * kyc * kyc)
435 + kxb * kxb * (kxc * kyd * kyd - 2.0f * kxd * kyc * kyd + kxd * kyc * kyc)
436 + kxb * (2.0f * kxd * kxd - 2.0f * kxc * kxd) * kyb * kyc
437 + (kxc * kxc * kxd - kxc * kxd * kxd) * kyb * kyb)
438 / (kxb * kxb * (kxd * kyc * kyc * kyd - kxc * kyc * kyd * kyd)
439 + kxb * kyb * (kxc * kxc * kyd * kyd - kxd * kxd * kyc * kyc)
440 + kyb * kyb * (kxc * kxd * kxd * kyc - kxc * kxc * kxd * kyd));
445 float e,
float g,
float h,
float kxa,
float kya)
447 const float xx =
i[0] - k_space[0];
448 const float yy =
i[1] - k_space[1];
450 const float div = ((
d * xx - a * yy) * h + (b * yy - e * xx) *
g + a * e - b *
d);
452 i[0] = (e * xx - b * yy) / div + kxa;
453 i[1] = -(
d * xx - a * yy) / div + kya;
458 float e,
float g,
float h,
float kxa,
float kya)
460 const float xx =
i[0] - kxa;
461 const float yy =
i[1] - kya;
463 const float div =
g * xx + h * yy + 1;
464 i[0] = (a * xx + b * yy) / div + k_space[0];
465 i[1] = (
d * xx + e * yy) / div + k_space[1];
469static inline
void backtransform(
float *
x,
float *o, const
float *
m, const
float t_h, const
float t_v)
471 x[1] /= (1.0f +
x[0] * t_h);
472 x[0] /= (1.0f +
x[1] * t_v);
479 const float det = (
m[0] *
m[3]) - (
m[1] *
m[2]);
480 inv_m[0] =
m[3] / det;
481 inv_m[1] = -
m[1] / det;
482 inv_m[2] = -
m[2] / det;
483 inv_m[3] =
m[0] / det;
487static inline
void transform(
float *
x,
float *o, const
float *
m, const
float t_h, const
float t_v)
490 o[1] *= (1.0f + o[0] * t_h);
491 o[0] *= (1.0f + o[1] * t_v);
500 float *
const restrict points,
size_t points_count)
517 const dt_boundingbox_t k_space = {
d->k_space[0] * rx,
d->k_space[1] * ry,
d->k_space[2] * rx,
d->k_space[3] * ry };
518 const float kxa =
d->kxa * rx, kxb =
d->kxb * rx, kxc =
d->kxc * rx, kxd =
d->kxd * rx;
519 const float kya =
d->kya * ry, kyb =
d->kyb * ry, kyc =
d->kyc * ry, kyd =
d->kyd * ry;
520 float ma = 0, mb = 0, md = 0, me = 0, mg = 0, mh = 0;
522 keystone_get_matrix(k_space, kxa, kxb, kxc, kxd, kya, kyb, kyc, kyd, &ma, &mb, &md, &me, &mg, &mh);
524 for(
size_t i = 0;
i < points_count * 2;
i += 2)
528 pi[1] = points[
i + 1];
548 points[
i] = po[0] - (
d->cix -
d->enlarge_x) /
factor;
549 points[
i + 1] = po[1] - (
d->ciy -
d->enlarge_y) /
factor;
564 float *
const restrict points,
size_t points_count)
581 const dt_boundingbox_t k_space = {
d->k_space[0] * rx,
d->k_space[1] * ry,
d->k_space[2] * rx,
d->k_space[3] * ry };
582 const float kxa =
d->kxa * rx, kxb =
d->kxb * rx, kxc =
d->kxc * rx, kxd =
d->kxd * rx;
583 const float kya =
d->kya * ry, kyb =
d->kyb * ry, kyc =
d->kyc * ry, kyd =
d->kyd * ry;
584 float ma = 0.0f, mb = 0.0f, md = 0.0f, me = 0.0f, mg = 0.0f, mh = 0.0f;
586 keystone_get_matrix(k_space, kxa, kxb, kxc, kxd, kya, kyb, kyc, kyd, &ma, &mb, &md, &me, &mg, &mh);
588 for(
size_t i = 0;
i < points_count * 2;
i += 2)
591 pi[0] = -(
d->enlarge_x -
d->cix) /
factor + points[
i];
592 pi[1] = -(
d->enlarge_y -
d->ciy) /
factor + points[
i + 1];
613 points[
i + 1] = po[1];
629 const float *
const in,
float *
const out,
const dt_iop_roi_t *
const roi_in,
645 const dt_boundingbox_t k_space = {
d->k_space[0] * rx,
d->k_space[1] * ry,
d->k_space[2] * rx,
d->k_space[3] * ry };
646 const float kxa =
d->kxa * rx, kxb =
d->kxb * rx, kxc =
d->kxc * rx, kxd =
d->kxd * rx;
647 const float kya =
d->kya * ry, kyb =
d->kyb * ry, kyc =
d->kyc * ry, kyd =
d->kyd * ry;
648 float ma = 0.0f, mb = 0.0f, md = 0.0f, me = 0.0f, mg = 0.0f, mh = 0.0f;
650 keystone_get_matrix(k_space, kxa, kxb, kxc, kxd, kya, kyb, kyc, kyd, &ma, &mb, &md, &me, &mg, &mh);
654 for(
int j = 0; j < roi_out->
height; j++)
656 float *_out =
out + (size_t)j * roi_out->
width;
657 for(
int i = 0;
i < roi_out->
width;
i++)
659 float pi[2] = { 0.0f }, po[2] = { 0.0f };
661 pi[0] = roi_out->
x - roi_out->
scale *
d->enlarge_x + roi_out->
scale *
d->cix +
i + 0.5f;
662 pi[1] = roi_out->
y - roi_out->
scale *
d->enlarge_y + roi_out->
scale *
d->ciy + j + 0.5f;
667 pi[1] -=
d->tx * roi_out->
scale;
668 pi[0] -=
d->ty * roi_out->
scale;
672 pi[0] -=
d->tx * roi_out->
scale;
673 pi[1] -=
d->ty * roi_out->
scale;
675 pi[0] /= roi_out->
scale;
676 pi[1] /= roi_out->
scale;
678 po[0] *= roi_in->
scale;
679 po[1] *= roi_in->
scale;
680 po[0] +=
d->tx * roi_in->
scale;
681 po[1] +=
d->ty * roi_in->
scale;
683 po[0] -= roi_in->
x + 0.5f;
684 po[1] -= roi_in->
y + 0.5f;
703 const float cx =
CLAMPF(
p->cx, 0.0f, 0.9f);
704 const float cy =
CLAMPF(
p->cy, 0.0f, 0.9f);
705 const float cw =
CLAMPF(fabsf(
p->cw), 0.1f, 1.0f);
706 const float ch =
CLAMPF(fabsf(
p->ch), 0.1f, 1.0f);
708 float points[8] = { 0.0f, 0.0f, wp, hp, cx * wp, cy * hp, cw * wp,
ch * hp };
713 g->clip_max_x = fmaxf(points[0], 0.0f);
714 g->clip_max_y = fmaxf(points[1], 0.0f);
715 g->clip_max_w = fminf(points[2] - points[0], 1.0f);
716 g->clip_max_h = fminf(points[3] - points[1], 1.0f);
719 g->clip_x = fmaxf(points[4],
g->clip_max_x);
720 g->clip_y = fmaxf(points[5],
g->clip_max_y);
721 g->clip_w = fminf(points[6] - points[4],
g->clip_max_w);
722 g->clip_h = fminf(points[7] - points[5],
g->clip_max_h);
754 float rt[] = { cosf(
d->angle), sinf(
d->angle), -sinf(
d->angle), cosf(
d->angle) };
757 rt[0] = rt[3] = 1.0f;
758 rt[1] = rt[2] = 0.0f;
761 for(
int k = 0;
k < 4;
k++)
d->m[
k] = rt[
k];
776 if(
d->k_apply == 0 &&
d->crop_auto == 1)
778 float inv_rt[4] = { 0.0f };
783 const float kc = 1.0f / fminf(roi_in->
width, roi_in->
height);
784 d->k_h =
d->ki_h * kc;
785 d->k_v =
d->ki_v * kc;
787 float cropscale = -1.0f;
795 float newcropscale = 1.0f;
798 aabb[4] = { -.5f * roi_in_width, -.5f * roi_in_height, .5f * roi_in_width, .5f * roi_in_height };
799 for(
int c = 0; c < 4; c++)
803 for(
int k = 0;
k < 2;
k++)
804 if(fabsf(o[
k]) > 0.001f) newcropscale = fminf(newcropscale, aabb[(o[
k] > 0 ? 2 : 0) +
k] / o[
k]);
806 if(newcropscale >= cropscale)
808 cropscale = newcropscale;
810 d->tx = roi_in->
width * .5f;
814 float ach =
d->ch -
d->cy, acw =
d->cw -
d->cx;
818 roi_out->
y =
d->tx - (.5f -
d->cy) * cropscale * roi_in->
width;
819 roi_out->
x =
d->ty - (.5f -
d->cx) * cropscale * roi_in->
height;
825 roi_out->
x =
d->tx - (.5f -
d->cx) * cropscale * roi_in->
width;
826 roi_out->
y =
d->ty - (.5f -
d->cy) * cropscale * roi_in->
height;
827 roi_out->
width = acw * cropscale * roi_in->
width;
849 for(
int c = 0; c < 4; c++)
856 o[0] /= (float)roi_in->
width;
857 o[1] /= (float)roi_in->
height;
859 o[0] *= roi_in->
width;
863 p[0] = o[0] - .5f * roi_in->
width;
864 p[1] = o[1] - .5f * roi_in->
height;
866 o[0] += .5f * roi_in->
width;
867 o[1] += .5f * roi_in->
height;
870 corn_out_x[c] = o[0];
871 corn_out_y[c] = o[1];
874 float new_x = fminf(fminf(fminf(corn_out_x[0], corn_out_x[1]), corn_out_x[2]), corn_out_x[3]);
875 if(new_x + roi_in->
width < 0) new_x = -roi_in->
width;
876 float new_y = fminf(fminf(fminf(corn_out_y[0], corn_out_y[1]), corn_out_y[2]), corn_out_y[3]);
879 float new_sc_x = fmaxf(fmaxf(fmaxf(corn_out_x[0], corn_out_x[1]), corn_out_x[2]), corn_out_x[3]);
880 if(new_sc_x > 2.0f * roi_in->
width) new_sc_x = 2.0f * roi_in->
width;
881 float new_sc_y = fmaxf(fmaxf(fmaxf(corn_out_y[0], corn_out_y[1]), corn_out_y[2]), corn_out_y[3]);
882 if(new_sc_y > 2.0f * roi_in->
height) new_sc_y = 2.0f * roi_in->
height;
885 if(new_sc_x - new_x < roi_in->
width / 8.0f)
887 float f = (new_sc_x + new_x) / 2.0f;
888 if(f < roi_in->
width / 16.0f)
f = roi_in->
width / 16.0f;
889 if(
f >= roi_in->
width * 15.0f / 16.0f)
f = roi_in->
width * 15.0f / 16.0f - 1.0f;
890 new_x =
f - roi_in->
width / 16.0f, new_sc_x =
f + roi_in->
width / 16.0f;
892 if(new_sc_y - new_y < roi_in->
height / 8.0f)
894 float f = (new_sc_y + new_y) / 2.0f;
896 if(
f >= roi_in->
height * 15.0f / 16.0f)
f = roi_in->
height * 15.0f / 16.0f - 1.0f;
897 new_y =
f - roi_in->
height / 16.0f, new_sc_y =
f + roi_in->
height / 16.0f;
900 new_sc_y = new_sc_y - new_y;
901 new_sc_x = new_sc_x - new_x;
904 new_x +=
d->cx * new_sc_x;
905 new_y +=
d->cy * new_sc_y;
906 new_sc_x *=
d->cw -
d->cx;
907 new_sc_y *=
d->ch -
d->cy;
909 d->enlarge_x = fmaxf(-new_x, 0.0f);
910 roi_out->
x = fmaxf(new_x, 0.0f);
911 d->enlarge_y = fmaxf(-new_y, 0.0f);
912 roi_out->
y = fmaxf(new_y, 0.0f);
914 roi_out->
width = new_sc_x;
915 roi_out->
height = new_sc_y;
916 d->tx = roi_in->
width * .5f;
921 if(roi_out->
x < 0) roi_out->
x = 0;
922 if(roi_out->
y < 0) roi_out->
y = 0;
950 const float so = roi_out->
scale;
952 const float roi_out_x = roi_out->
x -
d->enlarge_x * so, roi_out_y = roi_out->
y -
d->enlarge_y * so;
954 dt_boundingbox_t aabb = { roi_out_x +
d->cix * so, roi_out_y +
d->ciy * so, roi_out_x +
d->cix * so + roi_out->
width,
955 roi_out_y +
d->ciy * so + roi_out->
height };
957 for(
int c = 0; c < 4; c++)
991 roi_in->
x = aabb_in[0] - 1;
992 roi_in->
y = aabb_in[1] - 1;
993 roi_in->
width = aabb_in[2] - aabb_in[0] + 2;
994 roi_in->
height = aabb_in[3] - aabb_in[1] + 2;
996 if(
d->angle == 0.0f &&
d->all_off)
999 roi_in->
x = aabb_in[0];
1000 roi_in->
y = aabb_in[1];
1007 roi_in->
x = CLAMP(roi_in->
x, 0, (
int)floorf(scwidth));
1008 roi_in->
y = CLAMP(roi_in->
y, 0, (
int)floorf(scheight));
1009 roi_in->
width = CLAMP(roi_in->
width, 1, (
int)ceilf(scwidth) - roi_in->
x);
1010 roi_in->
height = CLAMP(roi_in->
height, 1, (
int)ceilf(scheight) - roi_in->
y);
1025 const int ch_width =
ch * roi_in->
width;
1028 if(!
d->flags &&
d->angle == 0.0 &&
d->all_off && roi_in->
width == roi_out->
width
1038 const dt_boundingbox_t k_space = {
d->k_space[0] * rx,
d->k_space[1] * ry,
d->k_space[2] * rx,
d->k_space[3] * ry };
1039 const float kxa =
d->kxa * rx, kxb =
d->kxb * rx, kxc =
d->kxc * rx, kxd =
d->kxd * rx;
1040 const float kya =
d->kya * ry, kyb =
d->kyb * ry, kyc =
d->kyc * ry, kyd =
d->kyd * ry;
1041 float ma = 0.0f, mb = 0.0f, md = 0.0f, me = 0.0f, mg = 0.0f, mh = 0.0f;
1043 keystone_get_matrix(k_space, kxa, kxb, kxc, kxd, kya, kyb, kyc, kyd, &ma, &mb, &md, &me, &mg, &mh);
1047 for(
int j = 0; j < roi_out->
height; j++)
1050 for(
int i = 0;
i < roi_out->
width;
i++)
1054 pi[0] = roi_out->
x - roi_out->
scale *
d->enlarge_x + roi_out->
scale *
d->cix +
i + 0.5f;
1055 pi[1] = roi_out->
y - roi_out->
scale *
d->enlarge_y + roi_out->
scale *
d->ciy + j + 0.5f;
1060 pi[1] -=
d->tx * roi_out->
scale;
1061 pi[0] -=
d->ty * roi_out->
scale;
1065 pi[0] -=
d->tx * roi_out->
scale;
1066 pi[1] -=
d->ty * roi_out->
scale;
1068 pi[0] /= roi_out->
scale;
1069 pi[1] /= roi_out->
scale;
1071 po[0] *= roi_in->
scale;
1072 po[1] *= roi_in->
scale;
1073 po[0] +=
d->tx * roi_in->
scale;
1074 po[1] +=
d->ty * roi_in->
scale;
1076 po[0] -= roi_in->
x + 0.5f;
1077 po[1] -= roi_in->
y + 0.5f;
1080 roi_in->
height, ch_width);
1110 d->m[0] =
d->m[3] = 1.0f;
1111 d->m[1] =
d->m[2] = 0.0f;
1112 d->ki_h =
d->ki_v =
d->k_h =
d->k_v = 0.0f;
1113 d->tx =
d->ty = 0.0f;
1114 d->cix =
d->ciy = 0.0f;
1115 d->kxa =
d->kxd =
d->kya =
d->kyb = 0.0f;
1116 d->kxb =
d->kxc =
d->kyc =
d->kyd = 0.6f;
1117 d->k_space[0] =
d->k_space[1] = 0.2f;
1118 d->k_space[2] =
d->k_space[3] = 0.6f;
1120 d->enlarge_x =
d->enlarge_y = 0.0f;
1122 d->angle =
M_PI / 180.0 *
p->angle;
1126 d->crop_auto =
p->crop_auto;
1134 if(fabsf(
p->k_h) >= .0001)
d->all_off = 0;
1135 if(
p->k_h >= -1.0 &&
p->k_h <= 1.0)
1139 if(fabsf(
p->k_v) >= .0001)
d->all_off = 0;
1140 if(
p->k_v >= -1.0 &&
p->k_v <= 1.0)
1145 else if(
p->k_type >= 0 &&
p->k_apply == 1)
1148 d->ki_h =
d->ki_v = 0;
1161 float a1 = (
d->kxd -
d->kxa) / (
d->kyd -
d->kya);
1162 float b1 =
d->kxa - a1 *
d->kya;
1163 float a2 = (
d->kxc -
d->kxb) / (
d->kyc -
d->kyb);
1164 float b2 =
d->kxb - a2 *
d->kyb;
1170 d->kxa = a1 *
d->kya + b1;
1176 d->kxb = a2 *
d->kyb + b2;
1183 d->kxd = a1 *
d->kyd + b1;
1189 d->kxc = a2 *
d->kyc + b2;
1192 else if(
p->k_type == 2)
1195 const float a1 = (
d->kyb -
d->kya) / (
d->kxb -
d->kxa);
1196 const float b1 =
d->kya - a1 *
d->kxa;
1197 const float a2 = (
d->kyc -
d->kyd) / (
d->kxc -
d->kxd);
1198 const float b2 =
d->kyd - a2 *
d->kxd;
1204 d->kya = a1 *
d->kxa + b1;
1210 d->kyd = a2 *
d->kxd + b2;
1217 d->kyb = a1 *
d->kxb + b1;
1223 d->kyc = a2 *
d->kxc + b2;
1226 d->k_space[0] = fabsf((
d->kxa +
d->kxd) / 2.0f);
1227 d->k_space[1] = fabsf((
d->kya +
d->kyb) / 2.0f);
1228 d->k_space[2] = fabsf((
d->kxb +
d->kxc) / 2.0f) -
d->k_space[0];
1229 d->k_space[3] = fabsf((
d->kyc +
d->kyd) / 2.0f) -
d->k_space[1];
1230 d->kxb =
d->kxb -
d->kxa;
1231 d->kxc =
d->kxc -
d->kxa;
1232 d->kxd =
d->kxd -
d->kxa;
1233 d->kyb =
d->kyb -
d->kya;
1234 d->kyc =
d->kyc -
d->kya;
1235 d->kyd =
d->kyd -
d->kya;
1236 keystone_get_matrix(
d->k_space,
d->kxa,
d->kxb,
d->kxc,
d->kxd,
d->kya,
d->kyb,
d->kyc,
d->kyd, &
d->a,
1237 &
d->b, &
d->d, &
d->e, &
d->g, &
d->h);
1260 d->cw =
CLAMPF(fabsf(
p->cw), 0.1f, 1.0f);
1261 d->ch =
CLAMPF(fabsf(
p->ch), 0.1f, 1.0f);
1263 if(
d->cx !=
p->cx ||
d->cy !=
p->cy ||
d->cw != fabsf(
p->cw) ||
d->ch != fabsf(
p->ch))
1265 fprintf(stderr,
"[crop&rotate] invalid crop data for %d : x=%0.04f y=%0.04f w=%0.04f h=%0.04f\n",
1280 g->preview_ready =
TRUE;
1302 g->clip_x =
CLAMPF(
p->cx, 0.0f, 0.9f);
1303 g->clip_y =
CLAMPF(
p->cy, 0.0f, 0.9f);
1304 g->clip_w =
CLAMPF(fabsf(
p->cw) -
p->cx, 0.1f, 1.0f -
g->clip_x);
1305 g->clip_h =
CLAMPF(fabsf(
p->ch) -
p->cy, 0.1f, 1.0f -
g->clip_y);
1314 if(
p->k_apply == 0 &&
p->k_type < 4 &&
p->k_type > 0)
1329 g->preview_ready =
TRUE;
1361 float *md,
float *me,
float *mg,
float *mh)
1363 k_space[0] =
d->k_space[0] * rx;
1364 k_space[1] =
d->k_space[1] * ry;
1365 k_space[2] =
d->k_space[2] * rx;
1366 k_space[3] =
d->k_space[3] * ry;
1371 keystone_get_matrix(k_space,
d->kxa * rx,
d->kxb * rx,
d->kxc * rx,
d->kxd * rx,
d->kya * ry,
1372 d->kyb * ry,
d->kyc * ry,
d->kyd * ry, ma, mb, md, me, mg, mh);
1384 float kxa = 0.f, kya = 0.f, ma = 0.f, mb = 0.f, md = 0.f, me = 0.f, mg = 0.f, mh = 0.f;
1385 _clipping_keystone(&
d, rx, ry, k_space, &kxa, &kya, &ma, &mb, &md, &me, &mg, &mh);
1387 for(
size_t i = 0;
i < points_count * 2;
i += 2)
1389 float pi[2] = { points[
i], points[
i + 1] }, po[2];
1408 points[
i] = po[0] - (
d.cix -
d.enlarge_x);
1409 points[
i + 1] = po[1] - (
d.ciy -
d.enlarge_y);
1423 float kxa = 0.f, kya = 0.f, ma = 0.f, mb = 0.f, md = 0.f, me = 0.f, mg = 0.f, mh = 0.f;
1424 _clipping_keystone(&
d, rx, ry, k_space, &kxa, &kya, &ma, &mb, &md, &me, &mg, &mh);
1426 for(
size_t i = 0;
i < points_count * 2;
i += 2)
1429 pi[0] = -(
d.enlarge_x -
d.cix) + points[
i];
1430 pi[1] = -(
d.enlarge_y -
d.ciy) + points[
i + 1];
1450 points[
i + 1] = po[1];
1468 record->
data = data;
1492 if(text && !g_strcmp0(text,_(
"original image")))
1494 int proc_iwd = 0, proc_iht = 0;
1497 if(!(proc_iwd > 0 && proc_iht > 0))
return 0.0f;
1499 if((
p->ratio_d > 0 && proc_iwd > proc_iht) || (
p->ratio_d < 0 && proc_iwd < proc_iht))
1500 return (
float)proc_iwd / (float)proc_iht;
1502 return (
float)proc_iht / (float)proc_iwd;
1509 const int iwd = mod_in.
width, iht = mod_in.
height;
1512 if(
p->ratio_d == -2 &&
p->ratio_n == -2)
1514 if(fabsf(
p->cw) == 1.0 &&
p->cx == 0.0 && fabsf(
p->ch) == 1.0 &&
p->cy == 0.0)
1522 const float whratio = ((float)(iwd - 2 * interpolation->
width) * (fabsf(
p->cw) -
p->cx))
1523 / ((float)(iht - 2 * interpolation->
width) * (fabsf(
p->ch) -
p->cy));
1524 const float ri = (float)iwd / (
float)iht;
1526 const float prec = 0.0003f;
1527 if(fabsf(whratio - 3.0f / 2.0f) < prec)
1532 else if(fabsf(whratio - 2.0f / 1.0f) < prec)
1537 else if(fabsf(whratio - 7.0f / 5.0f) < prec)
1542 else if(fabsf(whratio - 4.0f / 3.0f) < prec)
1547 else if(fabsf(whratio - 5.0f / 4.0f) < prec)
1552 else if(fabsf(whratio - 1.0f / 1.0f) < prec)
1557 else if(fabsf(whratio - 16.0f / 9.0f) < prec)
1562 else if(fabsf(whratio - 16.0f / 10.0f) < prec)
1567 else if(fabsf(whratio - 244.5f / 203.2f) < prec)
1572 else if(fabsf(whratio - sqrtf(2.0f)) < prec)
1574 p->ratio_d = 14142136;
1575 p->ratio_n = 10000000;
1577 else if(fabsf(whratio -
PHI) < prec)
1579 p->ratio_d = 16180340;
1580 p->ratio_n = 10000000;
1582 else if(fabsf(whratio - ri) < prec)
1595 if(
p->ratio_d == 0 &&
p->ratio_n == 0)
return -1.0f;
1596 float d = 1.0f,
n = 1.0f;
1599 d = copysignf(iwd,
p->ratio_d);
1609 const float dn = copysignf(
MAX(fabsf(
d), fabsf(
n)),
d);
1610 const float nn = copysignf(
MIN(fabsf(
d), fabsf(
n)),
n);
1630 if(iwd < iht) aspect = 1.0f / aspect;
1636 double clip_x =
MAX(iwd *
g->clip_x / (
float)iwd, 0.0f);
1637 double clip_y =
MAX(iht *
g->clip_y / (
float)iht, 0.0f);
1638 double clip_w =
MIN(iwd *
g->clip_w / (
float)iwd, 1.0f);
1639 double clip_h =
MIN(iht *
g->clip_h / (
float)iht, 1.0f);
1642 const double target_h = (
double)iwd *
g->clip_w / ((
double)iht * aspect);
1643 const double target_w = (
double)iht *
g->clip_h * aspect / (
double)iwd;
1651 clip_x = clip_x + clip_w - (target_w + clip_w) * .5;
1652 clip_y = clip_y + clip_h - (target_h + clip_h) * .5;
1653 clip_w = (target_w + clip_w) * .5;
1654 clip_h = (target_h + clip_h) * .5;
1658 clip_y = clip_y + clip_h - (target_h + clip_h) * .5;
1659 clip_w = (target_w + clip_w) * .5;
1660 clip_h = (target_h + clip_h) * .5;
1664 clip_w = (target_w + clip_w) * .5;
1665 clip_h = (target_h + clip_h) * .5;
1669 clip_h = (target_h + clip_h) * .5;
1670 clip_x = clip_x + clip_w - (target_w + clip_w) * .5;
1671 clip_w = (target_w + clip_w) * .5;
1676 const double off = target_h - clip_h;
1677 clip_h = clip_h + off;
1678 clip_y = clip_y - .5 * off;
1683 const double off = target_w - clip_w;
1684 clip_w = clip_w + off;
1685 clip_x = clip_x - .5 * off;
1688 if(clip_x < g->clip_max_x)
1690 double prev_clip_h = clip_h;
1691 clip_h *= (clip_w + clip_x -
g->clip_max_x) / clip_w;
1692 clip_w = clip_w + clip_x -
g->clip_max_x;
1693 clip_x =
g->clip_max_x;
1694 if(grab &
GRAB_TOP) clip_y += prev_clip_h - clip_h;
1696 if(clip_y < g->clip_max_y)
1698 double prev_clip_w = clip_w;
1699 clip_w *= (clip_h + clip_y -
g->clip_max_y) / clip_h;
1700 clip_h = clip_h + clip_y -
g->clip_max_y;
1701 clip_y =
g->clip_max_y;
1702 if(grab &
GRAB_LEFT) clip_x += prev_clip_w - clip_w;
1704 if(clip_x + clip_w >
g->clip_max_x +
g->clip_max_w)
1706 double prev_clip_h = clip_h;
1707 clip_h *= (
g->clip_max_x +
g->clip_max_w - clip_x) / clip_w;
1708 clip_w =
g->clip_max_x +
g->clip_max_w - clip_x;
1709 if(grab &
GRAB_TOP) clip_y += prev_clip_h - clip_h;
1711 if(clip_y + clip_h >
g->clip_max_y +
g->clip_max_h)
1713 double prev_clip_w = clip_w;
1714 clip_w *= (
g->clip_max_y +
g->clip_max_h - clip_y) / clip_h;
1715 clip_h =
g->clip_max_y +
g->clip_max_h - clip_y;
1716 if(grab &
GRAB_LEFT) clip_x += prev_clip_w - clip_w;
1718 g->clip_x = fmaxf(clip_x, 0.0f);
1719 g->clip_y = fmaxf(clip_y, 0.0f);
1720 g->clip_w = fminf(clip_w, 1.0f);
1721 g->clip_h = fminf(clip_h, 1.0f);
1748 return d->cx ==
p->cx &&
d->cy ==
p->cy &&
d->cw ==
p->cw &&
d->ch &&
p->cw;
1754 gboolean sep_found =
FALSE;
1755 char *
p = (
char *)num;
1762 if(sep_found) *
d *= 10;
1765 if(!sep_found && ((*
p ==
',') || (*
p ==
'.')))
1769 else if (*
p <
'0' || *
p >
'9')
1792 int d = abs(
p->ratio_d),
n =
p->ratio_n;
1798 const char *c = text;
1799 const char *end = text + strlen(text);
1800 while(*c !=
':' && *c !=
'/' && c < end) c++;
1805 int dd = atoi(text);
1808 if(nn == 0 || dd == 0)
1810 dt_control_log(_(
"invalid ratio format. it should be \"number:number\""));
1824 if(dd == 0 || nn == 0)
1826 dt_control_log(_(
"invalid ratio format. it should be a positive number"));
1840 while((nn % 2 == 0) && (dd % 2 == 0))
1848 if(nn % 2 == 0) nn /= 2;
1849 else if(dd % 2 == 0) dd /= 2;
1850 else if(nn > dd) nn = (nn - dd) / 2;
1851 else dd = (dd - nn) / 2;
1863 for(
const GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
1866 if(g_strcmp0(aspect->
name, text) == 0)
1876 if(
d != abs(
p->ratio_d) ||
n !=
p->ratio_n)
1892 int act = -1,
i = 0;
1894 for(
const GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
1897 if((aspect->
d ==
d) && (aspect->
n ==
n))
1912 snprintf(str,
sizeof(str),
"%d:%d %2.2f",
1913 abs(
p->ratio_d), abs(
p->ratio_n), (
float)abs(
p->ratio_d) / (
float)abs(
p->ratio_n));
1933 g->clip_w =
g->clip_x +
g->clip_w -
p->cx;
1939 g->clip_w =
p->cw -
g->clip_x;
1944 g->clip_h =
g->clip_y +
g->clip_h -
p->cy;
1950 g->clip_h =
p->ch -
g->clip_y;
1974 if((which == 5) || (which == 4 &&
p->k_h == 0 &&
p->k_v == 0))
1977 gtk_widget_set_sensitive(
g->crop_auto,
FALSE);
1978 gtk_widget_set_sensitive(
g->aspect_presets,
TRUE);
1984 if(which == 0 || which == 4)
1994 if(which == 0 || which == 4)
2000 gtk_widget_set_sensitive(
g->crop_auto, (
g->k_show == 0));
2001 gtk_widget_set_sensitive(
g->aspect_presets, (
g->k_show == 0));
2019 if(select < 0)
return;
2021 if(select > 10 &&
p->k_h == 0 &&
p->k_v == 0)
2023 else if(select > 10)
2060 if(
p->ratio_d == -1 &&
p->ratio_n == -1)
2066 const int d = abs(
p->ratio_d),
n =
p->ratio_n;
2070 for(
const GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
2073 if((aspect->
d ==
d) && (aspect->
n ==
n))
2082 if(
p->k_apply == 1)
g->k_show = 2;
2083 else g->k_show = -1;
2089 else if(
g->k_show == -1)
2100 snprintf(str,
sizeof(str),
"%d:%d %2.2f",
2101 abs(
p->ratio_d), abs(
p->ratio_n), (
float)abs(
p->ratio_d) / (
float)abs(
p->ratio_n));
2111 g->clip_x =
CLAMPF(
p->cx, 0.0f, 0.9f);
2112 g->clip_y =
CLAMPF(
p->cy, 0.0f, 0.9f);
2113 g->clip_w =
CLAMPF(fabsf(
p->cw) -
p->cx, 0.1f, 1.0f -
g->clip_x);
2114 g->clip_h =
CLAMPF(fabsf(
p->ch) -
p->cy, 0.1f, 1.0f -
g->clip_y);
2123 p->cw = copysignf(
p->cw, (
flip & 1) ? -1.0 : 1.0);
2124 p->ch = copysignf(
p->ch, (
flip & 2) ? -1.0 : 1.0);
2129 GdkModifierType modifier, gpointer
d)
2132 (
void)acceleratable;
2137 p->ratio_d = -
p->ratio_d;
2151 if((a->d == 0 || a->d == 1) && a->n == 0)
return -1;
2153 const float ad =
MAX(a->d, a->n);
2154 const float an =
MIN(a->d, a->n);
2155 const float bd =
MAX(b->d, b->n);
2156 const float bn =
MIN(b->d, b->n);
2157 const float aratio = ad / an;
2158 const float bratio = bd / bn;
2160 if(aratio < bratio)
return -1;
2162 const float prec = 0.0003f;
2163 if(fabsf(aratio - bratio) < prec)
return 0;
2172 if(bdim == 0)
return g_strdup(original);
2174 return g_strdup_printf(
"%s %4.2f", original, (
float)adim / (
float)bdim);
2181 g->aspect_list = NULL;
2182 g->clip_x =
g->clip_y =
g->handle_x =
g->handle_y = 0.0;
2183 g->clip_w =
g->clip_h = 1.0;
2184 g->clip_max_x =
g->clip_max_y = 0.0;
2185 g->clip_max_w =
g->clip_max_h = 1.0;
2188 g->straightening = 0;
2195 g->preview_ready =
FALSE;
2207 g_signal_connect(G_OBJECT(
g->hvflip),
"value-changed", G_CALLBACK(
hvflip_callback), self);
2208 gtk_widget_set_tooltip_text(
g->hvflip, _(
"mirror image horizontally and/or vertically"));
2214 gtk_widget_set_tooltip_text(
g->angle, _(
"right-click and drag a line on the image to drag a straight line"));
2222 gtk_widget_set_tooltip_text(
g->keystone_type, _(
"set perspective correction for your image"));
2227 gtk_widget_set_tooltip_text(
g->crop_auto, _(
"automatically crop to avoid black edges"));
2230 { _(
"original image"), 1, 0 },
2231 { _(
"square"), 1, 1 },
2232 { _(
"10:8 in print"), 2445, 2032 },
2233 { _(
"5:4, 4x5, 8x10"), 5, 4 },
2234 { _(
"11x14"), 14, 11 },
2235 { _(
"8.5x11, letter"), 110, 85 },
2236 { _(
"4:3, VGA, TV"), 4, 3 },
2238 { _(
"ISO 216, DIN 476, A4"), 14142136, 10000000 },
2239 { _(
"3:2, 4x6, 35mm"), 3, 2 },
2240 { _(
"16:10, 8x5"), 16, 10 },
2241 { _(
"golden cut"), 16180340, 10000000 },
2242 { _(
"16:9, HDTV"), 16, 9 },
2243 { _(
"widescreen"), 185, 100 },
2244 { _(
"2:1, univisium"), 2, 1 },
2245 { _(
"cinemascope"), 235, 100 },
2246 { _(
"21:9"), 237, 100 },
2247 { _(
"anamorphic"), 239, 100 },
2248 { _(
"3:1, panorama"), 300, 100 },
2253 for(
int i = 0;
i < aspects_count;
i++)
2257 aspect->
d = aspects[
i].
d;
2258 aspect->
n = aspects[
i].
n;
2259 g->aspect_list = g_list_append(
g->aspect_list, aspect);
2264 for(GSList *iter = custom_aspects; iter; iter = g_slist_next(iter))
2268 const char *c = nv->
value;
2269 const char *end = nv->
value + strlen(nv->
value);
2270 while(*c !=
':' && *c !=
'/' && c < end) c++;
2277 if(
n == 0 ||
d == 0)
2279 fprintf(stderr,
"invalid ratio format for `%s'. it should be \"number:number\"\n", nv->
key);
2280 dt_control_log(_(
"invalid ratio format for `%s'. it should be \"number:number\""), nv->
key);
2287 g->aspect_list = g_list_append(
g->aspect_list, aspect);
2291 fprintf(stderr,
"invalid ratio format for `%s'. it should be \"number:number\"\n", nv->
key);
2292 dt_control_log(_(
"invalid ratio format for `%s'. it should be \"number:number\""), nv->
key);
2305 for(GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
2308 int dd =
MIN(aspect->
d, aspect->
n);
2309 int nn =
MAX(aspect->
d, aspect->
n);
2310 if(dd ==
d && nn ==
n)
2314 GList *prev = g_list_previous(iter);
2315 g->aspect_list = g_list_delete_link(
g->aspect_list, iter);
2317 iter = prev ? prev :
g->aspect_list;
2330 for(GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
2339 gtk_widget_set_tooltip_text(
g->aspect_presets, _(
"set the aspect ratio\n"
2340 "the list is sorted: from most square to least square\n"
2341 "to enter custom aspect ratio open the combobox and type ratio in x:y or decimal format"));
2343 g_signal_connect(G_OBJECT(
g->aspect_presets),
"quad-pressed", G_CALLBACK(
aspect_flip), self);
2351 gtk_widget_set_tooltip_text(
g->cx, _(
"the left margin cannot overlap with the right margin"));
2358 gtk_widget_set_tooltip_text(
g->cw, _(
"the right margin cannot overlap with the left margin"));
2363 gtk_widget_set_tooltip_text(
g->cy, _(
"the top margin cannot overlap with the bottom margin"));
2370 gtk_widget_set_tooltip_text(
g->ch, _(
"the bottom margin cannot overlap with the top margin"));
2386 g->aspect_list = NULL;
2392 const float wd,
const float ht)
2395 if(!(pzx < g->clip_x || pzx >
g->clip_x +
g->clip_w || pzy < g->clip_y || pzy >
g->clip_y +
g->clip_h))
2399 if(pzx >=
g->clip_x && pzx * wd < g->clip_x * wd + border) grab |=
GRAB_LEFT;
2400 if(pzy >=
g->clip_y && pzy * ht < g->clip_y * ht + border) grab |=
GRAB_TOP;
2401 if(pzx <= g->clip_x +
g->clip_w && pzx * wd > (
g->clip_w +
g->clip_x) * wd - border)
2403 if(pzy <= g->clip_y +
g->clip_h && pzy * ht > (
g->clip_h +
g->clip_y) * ht - border)
2410static void gui_draw_sym(cairo_t *cr,
float x,
float y,
float scale, gboolean active)
2412 PangoLayout *layout;
2414 PangoFontDescription *desc = pango_font_description_copy_static(
dt_bauhaus_get_global()->pango_font_desc);
2415 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
2416 pango_font_description_set_absolute_size(desc,
DT_PIXEL_APPLY_DPI(16) * PANGO_SCALE * scale);
2417 layout = pango_cairo_create_layout(cr);
2418 pango_layout_set_font_description(layout, desc);
2419 pango_layout_set_text(layout,
"\352\235\217", -1);
2420 pango_layout_get_pixel_extents(layout, &ink, NULL);
2425 cairo_move_to(cr,
x - ink.width / 2.0f, y - 3.0 * ink.height / 4.0f -
DT_PIXEL_APPLY_DPI(4) * scale);
2427 cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, .9);
2429 cairo_set_source_rgba(cr, .2, .2, .2, .9);
2430 pango_cairo_show_layout(cr, layout);
2431 pango_font_description_free(desc);
2432 g_object_unref(layout);
2437 int32_t pointerx, int32_t pointery)
2445 if(!
g->preview_ready)
return;
2455 cairo_scale(cr, zoom_scale, zoom_scale);
2460 float pzxpy[2] = { (float)pointerx, (
float)pointery };
2462 const float pzx = pzxpy[0];
2463 const float pzy = pzxpy[1];
2466 cairo_set_source_rgba(cr, .2, .2, .2, .8);
2467 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
2468 cairo_rectangle(cr,
g->clip_max_x * wd - 1.f,
g->clip_max_y * ht - 1.f,
2469 g->clip_max_w * wd + 2.0,
g->clip_max_h * ht + 2.0);
2470 cairo_rectangle(cr,
g->clip_x * wd,
g->clip_y * ht,
g->clip_w * wd,
g->clip_h * ht);
2473 if(
g->clip_x > .0f ||
g->clip_y > .0f ||
g->clip_w < 1.0f ||
g->clip_h < 1.0f)
2475 cairo_set_line_width(cr, dashes / 2.0);
2476 cairo_rectangle(cr,
g->clip_x * wd,
g->clip_y * ht,
g->clip_w * wd,
g->clip_h * ht);
2484 char dimensions[16];
2485 dimensions[0] =
'\0';
2486 PangoLayout *layout;
2488 PangoFontDescription *desc = pango_font_description_copy_static(
dt_bauhaus_get_global()->pango_font_desc);
2489 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
2490 pango_font_description_set_absolute_size(desc,
DT_PIXEL_APPLY_DPI(16) * PANGO_SCALE / zoom_scale);
2491 layout = pango_cairo_create_layout(cr);
2492 pango_layout_set_font_description(layout, desc);
2496 snprintf(dimensions,
sizeof(dimensions),
"%.0f x %.0f", (
float)procw *
g->clip_w, (
float)proch *
g->clip_h);
2498 pango_layout_set_text(layout, dimensions, -1);
2499 pango_layout_get_pixel_extents(layout, NULL, &ext);
2500 const float text_w = ext.width;
2503 float xp = (
g->clip_x +
g->clip_w * .5f) * wd - text_w * .5f;
2504 float yp = (
g->clip_y +
g->clip_h * .5f) * ht - text_h * .5f;
2507 double x1, y1, x2, y2;
2508 cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
2509 xp =
CLAMPF(xp, x1 + 2.0 * margin, x2 - text_w - 2.0 * margin);
2510 yp =
CLAMPF(yp, y1 + 2.0 * margin, y2 - text_h - 2.0 * margin);
2512 cairo_set_source_rgba(cr, .5, .5, .5, .9);
2514 xp - margin, yp - margin);
2515 cairo_set_source_rgb(cr, .7, .7, .7);
2516 cairo_move_to(cr, xp, yp);
2517 pango_cairo_show_layout(cr, layout);
2518 pango_font_description_free(desc);
2519 g_object_unref(layout);
2523 dt_guides_draw(cr,
g->clip_x * wd,
g->clip_y * ht,
g->clip_w * wd,
g->clip_h * ht, zoom_scale);
2528 if(
g->straightening)
2531 PangoLayout *layout;
2532 PangoFontDescription *desc = pango_font_description_copy_static(
dt_bauhaus_get_global()->pango_font_desc);
2533 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
2534 pango_font_description_set_absolute_size(desc,
DT_PIXEL_APPLY_DPI(16) * PANGO_SCALE / zoom_scale);
2535 layout = pango_cairo_create_layout(cr);
2536 pango_layout_set_font_description(layout, desc);
2537 const float bzx =
g->button_down_zoom_x + .5f, bzy =
g->button_down_zoom_y + .5f;
2542 cairo_move_to(cr, bzx * wd, bzy * ht);
2543 cairo_line_to(cr, pzx * wd, pzy * ht);
2547 float dx = pzx * wd - bzx * wd, dy = pzy * ht - bzy * ht;
2553 float angle = atan2f(dy, dx);
2554 angle = angle * 180 /
M_PI;
2555 if(angle > 45.0) angle -= 90;
2556 if(angle < -45.0) angle += 90;
2558 char view_angle[16];
2559 view_angle[0] =
'\0';
2560 snprintf(view_angle,
sizeof(view_angle),
"%.2f\302\260", angle);
2561 pango_layout_set_text(layout, view_angle, -1);
2562 pango_layout_get_pixel_extents(layout, &ink, NULL);
2563 const float text_w = ink.width;
2566 cairo_set_source_rgba(cr, .5, .5, .5, .9);
2568 const float yp = pzy * ht - ink.height;
2570 (cr, text_w + 2 * margin, text_h + 2 * margin, xp - margin, yp - margin);
2571 cairo_set_source_rgba(cr, .7, .7, .7, .7);
2572 cairo_move_to(cr, xp, yp);
2573 pango_cairo_show_layout(cr, layout);
2574 pango_font_description_free(desc);
2575 g_object_unref(layout);
2577 else if(
g->k_show != 1)
2580 if(grab ==
GRAB_LEFT) cairo_rectangle(cr,
g->clip_x * wd,
g->clip_y * ht, border,
g->clip_h * ht);
2581 if(grab ==
GRAB_TOP) cairo_rectangle(cr,
g->clip_x * wd,
g->clip_y * ht,
g->clip_w * wd, border);
2582 if(grab ==
GRAB_TOP_LEFT) cairo_rectangle(cr,
g->clip_x * wd,
g->clip_y * ht, border, border);
2584 cairo_rectangle(cr, (
g->clip_x +
g->clip_w) * wd - border,
g->clip_y * ht, border,
g->clip_h * ht);
2586 cairo_rectangle(cr,
g->clip_x * wd, (
g->clip_y +
g->clip_h) * ht - border,
g->clip_w * wd, border);
2588 cairo_rectangle(cr, (
g->clip_x +
g->clip_w) * wd - border, (
g->clip_y +
g->clip_h) * ht - border,
2591 cairo_rectangle(cr, (
g->clip_x +
g->clip_w) * wd - border,
g->clip_y * ht, border, border);
2593 cairo_rectangle(cr,
g->clip_x * wd, (
g->clip_y +
g->clip_h) * ht - border, border, border);
2598 if(
g->k_show == 1 &&
p->k_type > 0)
2604 const float wp = mod_out.
width, hp = mod_out.
height;
2605 float pts[8] = {
p->kxa * wp,
p->kya * hp,
p->kxb * wp,
p->kyb * hp,
2606 p->kxc * wp,
p->kyc * hp,
p->kxd * wp,
p->kyd * hp };
2612 const float v1t = pts[0] - (pts[6] - pts[0]) * pts[1] / (pts[7] - pts[1]);
2613 const float v1b = (pts[6] - pts[0]) * ht / (pts[7] - pts[1]) + v1t;
2614 const float v2t = pts[2] - (pts[4] - pts[2]) * pts[3] / (pts[5] - pts[3]);
2615 const float v2b = (pts[4] - pts[2]) * ht / (pts[5] - pts[3]) + v2t;
2616 const float h1l = pts[1] - (pts[3] - pts[1]) * pts[0] / (pts[2] - pts[0]);
2617 const float h1r = (pts[3] - pts[1]) * wd / (pts[2] - pts[0]) + h1l;
2618 const float h2l = pts[7] - (pts[5] - pts[7]) * pts[6] / (pts[4] - pts[6]);
2619 const float h2r = (pts[5] - pts[7]) * wd / (pts[4] - pts[6]) + h2l;
2622 cairo_move_to(cr, v1t, 0);
2623 cairo_line_to(cr, v1b, ht);
2625 cairo_move_to(cr, v2t, 0);
2626 cairo_line_to(cr, v2b, ht);
2628 cairo_move_to(cr, 0, h1l);
2629 cairo_line_to(cr, wd, h1r);
2631 cairo_move_to(cr, 0, h2l);
2632 cairo_line_to(cr, wd, h2r);
2636 if(
g->k_selected_segment == 0)
2638 cairo_move_to(cr, pts[0], pts[1]);
2639 cairo_line_to(cr, pts[2], pts[3]);
2642 else if(
g->k_selected_segment == 1)
2644 cairo_move_to(cr, pts[4], pts[5]);
2645 cairo_line_to(cr, pts[2], pts[3]);
2648 else if(
g->k_selected_segment == 2)
2650 cairo_move_to(cr, pts[4], pts[5]);
2651 cairo_line_to(cr, pts[6], pts[7]);
2654 else if(
g->k_selected_segment == 3)
2656 cairo_move_to(cr, pts[0], pts[1]);
2657 cairo_line_to(cr, pts[6], pts[7]);
2661 else if(
p->k_type == 2)
2664 const float h1l = pts[1] - (pts[3] - pts[1]) * pts[0] / (pts[2] - pts[0]);
2665 const float h1r = (pts[3] - pts[1]) * wd / (pts[2] - pts[0]) + h1l;
2666 const float h2l = pts[7] - (pts[5] - pts[7]) * pts[6] / (pts[4] - pts[6]);
2667 const float h2r = (pts[5] - pts[7]) * wd / (pts[4] - pts[6]) + h2l;
2670 cairo_move_to(cr, 0, h1l);
2671 cairo_line_to(cr, wd, h1r);
2673 cairo_move_to(cr, 0, h2l);
2674 cairo_line_to(cr, wd, h2r);
2678 if(
g->k_selected_segment == 1)
2680 cairo_move_to(cr, pts[4], pts[5]);
2681 cairo_line_to(cr, pts[2], pts[3]);
2684 else if(
g->k_selected_segment == 3)
2686 cairo_move_to(cr, pts[0], pts[1]);
2687 cairo_line_to(cr, pts[6], pts[7]);
2691 else if(
p->k_type == 1)
2694 const float v1t = pts[0] - (pts[6] - pts[0]) * pts[1] / (pts[7] - pts[1]);
2695 const float v1b = (pts[6] - pts[0]) * ht / (pts[7] - pts[1]) + v1t;
2696 const float v2t = pts[2] - (pts[4] - pts[2]) * pts[3] / (pts[5] - pts[3]);
2697 const float v2b = (pts[4] - pts[2]) * ht / (pts[5] - pts[3]) + v2t;
2700 cairo_move_to(cr, v1t, 0);
2701 cairo_line_to(cr, v1b, ht);
2703 cairo_move_to(cr, v2t, 0);
2704 cairo_line_to(cr, v2b, ht);
2708 if(
g->k_selected_segment == 0)
2710 cairo_move_to(cr, pts[0], pts[1]);
2711 cairo_line_to(cr, pts[2], pts[3]);
2714 else if(
g->k_selected_segment == 2)
2716 cairo_move_to(cr, pts[4], pts[5]);
2717 cairo_line_to(cr, pts[6], pts[7]);
2723 if(
g->k_selected == 0)
2726 cairo_set_source_rgba(cr, 1.0, 0, 0, .8);
2731 cairo_set_source_rgba(cr, 1.0, 0, 0, .5);
2735 if(
g->k_selected == 1)
2738 cairo_set_source_rgba(cr, 1.0, 0, 0, .8);
2743 cairo_set_source_rgba(cr, 1.0, 0, 0, .5);
2747 if(
g->k_selected == 2)
2750 cairo_set_source_rgba(cr, 1.0, 0, 0, .8);
2755 cairo_set_source_rgba(cr, 1.0, 0, 0, .5);
2759 if(
g->k_selected == 3)
2762 cairo_set_source_rgba(cr, 1.0, 0, 0, .8);
2767 cairo_set_source_rgba(cr, 1.0, 0, 0, .5);
2772 PangoLayout *layout;
2774 PangoFontDescription *desc = pango_font_description_copy_static(
dt_bauhaus_get_global()->pango_font_desc);
2775 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
2776 pango_font_description_set_absolute_size(desc,
DT_PIXEL_APPLY_DPI(16) * PANGO_SCALE);
2777 layout = pango_cairo_create_layout(cr);
2778 pango_layout_set_font_description(layout, desc);
2780 pango_layout_set_text(layout,
"ok", -1);
2781 pango_layout_get_pixel_extents(layout, &ink, NULL);
2782 int c[2] = { (
MIN(pts[4], pts[2]) +
MAX(pts[0], pts[6])) / 2.0f,
2783 (
MIN(pts[5], pts[7]) +
MAX(pts[1], pts[3])) / 2.0f };
2784 cairo_set_source_rgba(cr, .5, .5, .5, .9);
2789 cairo_move_to(cr, c[0] - ink.width / 2.0, c[1] - 3.0 * ink.height / 4.0);
2791 pango_cairo_show_layout(cr, layout);
2792 pango_font_description_free(desc);
2793 g_object_unref(layout);
2796 gboolean sym =
FALSE;
2797 if(
p->k_type == 1 ||
p->k_type == 3)
2799 if(
p->k_sym == 1 ||
p->k_sym == 3) sym =
TRUE;
2800 gui_draw_sym(cr, (pts[0] + pts[6]) / 2.0f, (pts[1] + pts[7]) / 2.0f, 1.f, sym);
2801 gui_draw_sym(cr, (pts[2] + pts[4]) / 2.0f, (pts[3] + pts[5]) / 2.0f, 1.f, sym);
2803 if(
p->k_type == 2 ||
p->k_type == 3)
2805 sym = (
p->k_sym >= 2);
2806 gui_draw_sym(cr, (pts[0] + pts[2]) / 2.0f, (pts[1] + pts[3]) / 2.0f, 1.f, sym);
2807 gui_draw_sym(cr, (pts[6] + pts[4]) / 2.0f, (pts[7] + pts[5]) / 2.0f, 1.f, sym);
2814static float dist_seg(
float xa,
float ya,
float xb,
float yb,
float xc,
float yc)
2816 if(xa == xb && ya == yb)
return (xc - xa) * (xc - xa) + (yc - ya) * (yc - ya);
2818 const float sx = xb - xa;
2819 const float sy = yb - ya;
2821 const float ux = xc - xa;
2822 const float uy = yc - ya;
2824 const float dp = sx * ux + sy * uy;
2825 if(dp < 0)
return (xc - xa) * (xc - xa) + (yc - ya) * (yc - ya);
2827 const float sn2 = sx * sx + sy * sy;
2828 if(dp > sn2)
return (xc - xb) * (xc - xb) + (yc - yb) * (yc - yb);
2830 const float ah2 = dp * dp / sn2;
2831 const float un2 = ux * ux + uy * uy;
2842 if(!
g->preview_ready)
return 0;
2847 float pzxpy[2] = { (float)
x, (
float)y };
2849 float pzx = pzxpy[0];
2850 float pzy = pzxpy[1];
2858 g->straightening = 1;
2865 if(
g->k_drag ==
TRUE &&
g->k_selected >= 0)
2867 float pts[2] = { pzx * wd, pzy * ht };
2871 const float xx = pts[0] / (float)mod_out.
width, yy = pts[1] / (
float)mod_out.
height;
2872 if(
g->k_selected == 0)
2874 if(
p->k_sym == 1 ||
p->k_sym == 3)
2875 p->kxa = fminf(xx, (
p->kxc +
p->kxd - 0.01f) / 2.0f),
p->kxb =
p->kxc -
p->kxa +
p->kxd;
2877 p->kxa = fminf(xx,
p->kxb - 0.01f);
2879 p->kya = fminf(yy, (
p->kyc +
p->kyb - 0.01f) / 2.0f),
p->kyd =
p->kyc -
p->kya +
p->kyb;
2881 p->kya = fminf(yy,
p->kyd - 0.01f);
2883 else if(
g->k_selected == 1)
2885 if(
p->k_sym == 1 ||
p->k_sym == 3)
2886 p->kxb = fmaxf(xx, (
p->kxc +
p->kxd + 0.01f) / 2.0f),
p->kxa =
p->kxc -
p->kxb +
p->kxd;
2888 p->kxb = fmaxf(xx,
p->kxa + 0.01f);
2890 p->kyb = fminf(yy, (
p->kya +
p->kyd - 0.01f) / 2.0f),
p->kyc =
p->kya -
p->kyb +
p->kyd;
2892 p->kyb = fminf(yy,
p->kyc - 0.01f);
2894 else if(
g->k_selected == 2)
2896 if(
p->k_sym == 1 ||
p->k_sym == 3)
2897 p->kxc = fmaxf(xx, (
p->kxa +
p->kxb + 0.01f) / 2.0f),
p->kxd =
p->kxa -
p->kxc +
p->kxb;
2899 p->kxc = fmaxf(xx,
p->kxd + 0.01f);
2901 p->kyc = fmaxf(yy, (
p->kya +
p->kyd + 0.01f) / 2.0f),
p->kyb =
p->kya -
p->kyc +
p->kyd;
2903 p->kyc = fmaxf(yy,
p->kyb + 0.01f);
2905 else if(
g->k_selected == 3)
2907 if(
p->k_sym == 1 ||
p->k_sym == 3)
2908 p->kxd = fminf(xx, (
p->kxa +
p->kxb - 0.01f) / 2.0f),
p->kxc =
p->kxa -
p->kxd +
p->kxb;
2910 p->kxd = fminf(xx,
p->kxc - 0.01f);
2912 p->kyd = fmaxf(yy, (
p->kyc +
p->kyb + 0.01f) / 2.0f),
p->kya =
p->kyc -
p->kyd +
p->kyb;
2914 p->kyd = fmaxf(yy,
p->kya + 0.01f);
2921 if(
g->k_drag ==
TRUE &&
g->k_selected_segment >= 0)
2923 float decalx = pzx -
g->button_down_zoom_x;
2924 float decaly = pzy -
g->button_down_zoom_y;
2925 if(
g->k_selected_segment == 0 && (
p->k_type == 1 ||
p->k_type == 3))
2927 decaly = fminf(decaly,
p->kyd -
p->kya);
2928 decaly = fminf(decaly,
p->kyc -
p->kyb);
2934 else if(
g->k_selected_segment == 1 && (
p->k_type == 2 ||
p->k_type == 3))
2936 decalx = fmaxf(decalx,
p->kxa -
p->kxb);
2937 decalx = fmaxf(decalx,
p->kxd -
p->kxc);
2943 else if(
g->k_selected_segment == 2 && (
p->k_type == 1 ||
p->k_type == 3))
2945 decaly = fmaxf(decaly,
p->kya -
p->kyd);
2946 decaly = fmaxf(decaly,
p->kyb -
p->kyc);
2952 else if(
g->k_selected_segment == 3 && (
p->k_type == 2 ||
p->k_type == 3))
2954 decalx = fminf(decalx,
p->kxb -
p->kxa);
2955 decalx = fminf(decalx,
p->kxc -
p->kxd);
2961 g->button_down_zoom_x = pzx;
2962 g->button_down_zoom_y = pzy;
2969 const float bzx =
g->button_down_zoom_x + .5f, bzy =
g->button_down_zoom_y + .5f;
2970 if(
g->cropping ==
GRAB_CENTER && !
g->straightening &&
g->k_show != 1)
2976 g->handle_x =
g->clip_x;
2977 g->handle_y =
g->clip_y;
2979 if(grab &
GRAB_LEFT)
g->handle_x = bzx -
g->clip_x;
2980 if(grab &
GRAB_TOP)
g->handle_y = bzy -
g->clip_y;
2981 if(grab &
GRAB_RIGHT)
g->handle_x = bzx - (
g->clip_w +
g->clip_x);
2982 if(grab &
GRAB_BOTTOM)
g->handle_y = bzy - (
g->clip_h +
g->clip_y);
2994 = fminf(
g->clip_max_w +
g->clip_max_x -
g->clip_w, fmaxf(
g->clip_max_x,
g->handle_x + pzx - bzx));
2998 = fminf(
g->clip_max_h +
g->clip_max_y -
g->clip_h, fmaxf(
g->clip_max_y,
g->handle_y + pzy - bzy));
3011 float ratio = fmaxf((
g->prev_clip_w - 2.0f * xx) /
g->prev_clip_w,
3012 (
g->prev_clip_h - 2.0f * yy) /
g->prev_clip_h);
3015 if(
g->prev_clip_w * ratio < 0.1f) ratio = 0.1f /
g->prev_clip_w;
3016 if(
g->prev_clip_h * ratio < 0.1f) ratio = 0.1f /
g->prev_clip_h;
3019 if(
g->prev_clip_w * ratio >
g->clip_max_w) ratio =
g->clip_max_w /
g->prev_clip_w;
3020 if(
g->prev_clip_h * ratio >
g->clip_max_h) ratio =
g->clip_max_h /
g->prev_clip_h;
3023 float nx =
g->prev_clip_x - (
g->prev_clip_w * ratio -
g->prev_clip_w) / 2.0f;
3024 float ny =
g->prev_clip_y - (
g->prev_clip_h * ratio -
g->prev_clip_h) / 2.0f;
3025 float nw =
g->prev_clip_w * ratio;
3026 float nh =
g->prev_clip_h * ratio;
3029 nx = fmaxf(nx,
g->clip_max_x);
3031 nx = fminf(nx,
g->clip_max_w +
g->clip_max_x - nw);
3033 ny = fmaxf(ny,
g->clip_max_y);
3035 ny = fminf(ny,
g->clip_max_h +
g->clip_max_y - nh);
3047 const float old_clip_x =
g->clip_x;
3048 g->clip_x = fminf(fmaxf(
g->clip_max_x, pzx -
g->handle_x),
g->clip_x +
g->clip_w - 0.1f);
3049 g->clip_w = old_clip_x +
g->clip_w -
g->clip_x;
3053 const float old_clip_y =
g->clip_y;
3054 g->clip_y = fminf(fmaxf(
g->clip_max_y, pzy -
g->handle_y),
g->clip_y +
g->clip_h - 0.1f);
3055 g->clip_h = old_clip_y +
g->clip_h -
g->clip_y;
3058 g->clip_w = fmaxf(0.1f, fminf(
g->clip_max_w +
g->clip_max_x, pzx -
g->clip_x -
g->handle_x));
3060 g->clip_h = fmaxf(0.1f, fminf(
g->clip_max_h +
g->clip_max_y, pzy -
g->clip_y -
g->handle_y));
3063 if(
g->clip_x +
g->clip_w >
g->clip_max_w +
g->clip_max_x)
3064 g->clip_w =
g->clip_max_w +
g->clip_max_x -
g->clip_x;
3065 if(
g->clip_y +
g->clip_h >
g->clip_max_h +
g->clip_max_y)
3066 g->clip_h =
g->clip_max_h +
g->clip_max_y -
g->clip_y;
3072 = {
g->clip_x * wd,
g->clip_y * ht, (
g->clip_x +
g->clip_w) * wd, (
g->clip_y +
g->clip_h) * ht };
3102 else if(grab &&
g->k_show != 1)
3129 "<b>straighten</b>: right-drag"));
3136 g->straightening =
g->cropping = 0;
3140 if(
g->k_show == 1 &&
g->k_drag ==
FALSE)
3142 float pts[2] = { pzx * wd, pzy * ht };
3146 float xx = pts[0] / (float)mod_out.
width, yy = pts[1] / (
float)mod_out.
height;
3149 g->k_selected_segment = -1;
3150 if(xx < p->kxa + ext && xx >
p->kxa - ext && yy < p->kya + ext && yy >
p->kya - ext)
g->k_selected = 0;
3151 if(xx < p->kxb + ext && xx >
p->kxb - ext && yy < p->kyb + ext && yy >
p->kyb - ext)
g->k_selected = 1;
3152 if(xx < p->kxc + ext && xx >
p->kxc - ext && yy < p->kyc + ext && yy >
p->kyc - ext)
g->k_selected = 2;
3153 if(xx < p->kxd + ext && xx >
p->kxd - ext && yy < p->kyd + ext && yy >
p->kyd - ext)
g->k_selected = 3;
3155 if(
g->k_selected < 0)
3157 if(
p->k_type == 1 ||
p->k_type == 3)
3159 if(
dist_seg(
p->kxa,
p->kya,
p->kxb,
p->kyb, xx, yy) < ext * ext)
3160 g->k_selected_segment = 0;
3161 else if(
dist_seg(
p->kxd,
p->kyd,
p->kxc,
p->kyc, xx, yy) < ext * ext)
3162 g->k_selected_segment = 2;
3163 if(
dist_seg(
p->kxb,
p->kyb,
p->kxc,
p->kyc, xx, yy) < ext * ext)
3164 g->k_selected_segment = 1;
3165 else if(
dist_seg(
p->kxd,
p->kyd,
p->kxa,
p->kya, xx, yy) < ext * ext)
3166 g->k_selected_segment = 3;
3169 if(
g->k_selected >= 0)
3174 else if(
g->k_selected_segment >= 0)
3182 "<b>move line/control point</b>: drag"));
3189 "<b>straighten</b>: right-drag, <b>commit</b>: double-click"));
3201 const float eps = 1e-6f;
3206 p->cx =
p->cy = 0.0f;
3207 p->cw =
p->ch = 1.0f;
3213 = {
g->clip_x * wd,
g->clip_y * ht, (
g->clip_x +
g->clip_w) * wd, (
g->clip_y +
g->clip_h) * ht };
3219 p->cx =
CLAMPF(points[0] / (
float)mod_out.
width, 0.0f, 0.9f);
3220 p->cy =
CLAMPF(points[1] / (
float)mod_out.
height, 0.0f, 0.9f);
3221 p->cw = copysignf(
CLAMPF(points[2] / (
float)mod_out.
width, 0.1f, 1.0f),
p->cw);
3222 p->ch = copysignf(
CLAMPF(points[3] / (
float)mod_out.
height, 0.1f, 1.0f),
p->ch);
3226 const gboolean changed = fabs(
p->cx - old[0]) >
eps || fabs(
p->cy - old[1]) >
eps || fabs(
p->cw - old[2]) >
eps || fabs(
p->ch - old[3]) >
eps;
3235 if(!
g->preview_ready)
return 0;
3237 if(
g->straightening)
3243 float dx = pts[0] - pts[2];
3244 float dy = pts[1] - pts[3];
3251 float angle = atan2f(dy, dx);
3252 if(!(angle >= -
M_PI / 2.0 && angle <=
M_PI / 2.0)) angle = 0.0f;
3253 float close = angle;
3254 if(close >
M_PI / 4.0)
3255 close =
M_PI / 2.0 - close;
3256 else if(close < -
M_PI / 4.0)
3257 close = -
M_PI / 2.0 - close;
3261 float a = 180.0 /
M_PI * close;
3262 if(a < -180.0) a += 360.0;
3263 if(a > 180.0) a -= 360.0;
3268 if(
g->k_drag)
g->k_drag =
FALSE;
3271 g->straightening =
g->cropping = 0;
3286 if(!
g->preview_ready)
return 0;
3289 if(
type == GDK_2BUTTON_PRESS && which == 1)
3295 if(which == 3 || which == 1)
3302 if(
g->k_selected >= 0)
3307 float pzxpy[2] = { (float)
x, (
float)y };
3309 float pzx = pzxpy[0];
3310 float pzy = pzxpy[1];
3314 const float wp = mod_out.
width, hp = mod_out.
height;
3315 float pts[8] = {
p->kxa * wp,
p->kya * hp,
p->kxb * wp,
p->kyb * hp,
3316 p->kxc * wp,
p->kyc * hp,
p->kxd * wp,
p->kyd * hp };
3319 float point[2] = { pzx, pzy };
3321 const float xx =
point[0];
3322 const float yy =
point[1];
3323 float c[2] = { (
MIN(pts[4], pts[2]) +
MAX(pts[0], pts[6])) / 2.0f,
3324 (
MIN(pts[5], pts[7]) +
MAX(pts[1], pts[3])) / 2.0f };
3327 if(xx > c[0] - ext && xx < c[0] + ext && yy > c[1] - ext && yy < c[1] + ext)
3342 c[0] = (pts[0] + pts[6]) / 2.0f, c[1] = (pts[1] + pts[7]) / 2.0f;
3343 if(xx > c[0] - ext && xx < c[0] + ext && yy > c[1] - ext && yy < c[1] + ext
3344 && (
p->k_type == 1 ||
p->k_type == 3))
3348 else if(
p->k_sym == 1)
3350 else if(
p->k_sym == 2)
3358 c[0] = (pts[2] + pts[4]) / 2.0f, c[1] = (pts[3] + pts[5]) / 2.0f;
3359 if(xx > c[0] - ext && xx < c[0] + ext && yy > c[1] - ext && yy < c[1] + ext
3360 && (
p->k_type == 1 ||
p->k_type == 3))
3364 else if(
p->k_sym == 1)
3366 else if(
p->k_sym == 2)
3374 c[0] = (pts[2] + pts[0]) / 2.0f, c[1] = (pts[3] + pts[1]) / 2.0f;
3375 if(xx > c[0] - ext && xx < c[0] + ext && yy > c[1] - ext && yy < c[1] + ext
3376 && (
p->k_type == 2 ||
p->k_type == 3))
3380 else if(
p->k_sym == 1)
3382 else if(
p->k_sym == 2)
3390 c[0] = (pts[4] + pts[6]) / 2.0f, c[1] = (pts[5] + pts[7]) / 2.0f;
3391 if(xx > c[0] - ext && xx < c[0] + ext && yy > c[1] - ext && yy < c[1] + ext
3392 && (
p->k_type == 2 ||
p->k_type == 3))
3396 else if(
p->k_sym == 1)
3398 else if(
p->k_sym == 2)
3406 if(
g->k_selected_segment >= 0)
3408 float border_pzxpy[2] = { (float)
x, (
float)y };
3410 pzx = border_pzxpy[0];
3411 pzy = border_pzxpy[1];
3412 g->button_down_zoom_x += 0.5;
3413 g->button_down_zoom_y += 0.5;
3425 float button_down_xy[2] = { (float)
x, (
float)y };
3427 g->button_down_x = button_down_xy[0];
3428 g->button_down_y = button_down_xy[1];
3429 g->button_down_angle =
p->angle;
3432 g->prev_clip_x =
g->clip_x;
3433 g->prev_clip_y =
g->clip_y;
3434 g->prev_clip_w =
g->clip_w;
3435 g->prev_clip_h =
g->clip_h;
Handle default and user-set shortcuts (accelerators)
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)
void dt_bauhaus_combobox_set_text(GtkWidget *widget, const char *text)
int dt_bauhaus_combobox_get(GtkWidget *widget)
void dt_bauhaus_slider_set_offset(GtkWidget *widget, float offset)
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
void dt_bauhaus_slider_set_soft_min(GtkWidget *widget, float val)
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_slider_set_format(GtkWidget *widget, const char *format)
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)
void dt_bauhaus_slider_set_factor(GtkWidget *widget, float factor)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
int operation_tags_filter()
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 void commit_box(dt_iop_module_t *self, dt_iop_clipping_gui_data_t *g, dt_iop_clipping_params_t *p)
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 _grab_region_t get_grab(float pzx, float pzy, dt_iop_clipping_gui_data_t *g, const float border, const float wd, const float ht)
static int _iop_clipping_set_max_clip(struct dt_iop_module_t *self)
const char ** description(struct dt_iop_module_t *self)
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)
static void free_aspect(gpointer data)
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
static gchar * format_aspect(gchar *original, int adim, int bdim)
static void keystone_backtransform(float *i, const dt_boundingbox_t k_space, float a, float b, float d, float e, float g, float h, float kxa, float kya)
static float _ratio_get_aspect(dt_iop_module_t *self, GtkWidget *combo)
static gint _aspect_ratio_cmp(const dt_iop_clipping_aspect_t *a, const dt_iop_clipping_aspect_t *b)
static void _clipping_derive(dt_iop_clipping_data_t *d, const dt_iop_roi_t *const roi_in_orig, dt_iop_roi_t *roi_out)
Derive this module's whole geometric state, and the output rect, from the committed parameters and th...
static int _clipping_geometry_transform(const void *data, const dt_geometry_record_t *const record, dt_geometry_chain_t *chain, float *points, size_t points_count)
static void _event_preview_updated_callback(gpointer instance, dt_iop_module_t *self)
static void hvflip_callback(GtkWidget *widget, dt_iop_module_t *self)
static const dt_geometry_vtable_t _clipping_geometry_vtable
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 void _float_to_fract(const char *num, int *n, int *d)
static void _clipping_resolve(struct dt_iop_module_t *self, const dt_iop_clipping_params_t *const p, dt_iop_clipping_data_t *d)
Parameters -> committed data. THE constructor.
static void get_corner(const float *aabb, const int i, float *p)
static void backtransform(float *x, float *o, const float *m, const float t_h, const float t_v)
static void apply_box_aspect(dt_iop_module_t *self, _grab_region_t grab)
static void _clipping_geometry_map_size(const void *data, const dt_iop_roi_t *const in, dt_iop_roi_t *out)
void gui_focus(struct dt_iop_module_t *self, gboolean in)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static int _clipping_geometry_backtransform(const void *data, const dt_geometry_record_t *const record, dt_geometry_chain_t *chain, float *points, size_t points_count)
static void keystone_transform(float *i, const dt_boundingbox_t k_space, float a, float b, float d, float e, float g, float h, float kxa, float kya)
static void _clipping_keystone(const dt_iop_clipping_data_t *const d, const float rx, const float ry, dt_boundingbox_t k_space, float *kxa, float *kya, float *ma, float *mb, float *md, float *me, float *mg, float *mh)
The keystone matrix and the scaled quadrilateral, which both directions need.
void gui_reset(struct dt_iop_module_t *self)
void gui_update(struct dt_iop_module_t *self)
void gui_init(struct dt_iop_module_t *self)
int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
static void aspect_presets_changed(GtkWidget *combo, dt_iop_module_t *self)
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
int button_released(struct dt_iop_module_t *self, double x, double y, int which, uint32_t state)
static int gui_has_focus(struct dt_iop_module_t *self)
static void keystone_type_populate(struct dt_iop_module_t *self, gboolean with_applied, int select)
void reload_defaults(dt_iop_module_t *self)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
void gui_cleanup(struct dt_iop_module_t *self)
static void keystone_type_changed(GtkWidget *combo, dt_iop_module_t *self)
static void adjust_aabb(const float *p, float *aabb)
static float dist_seg(float xa, float ya, float xb, float yb, float xc, float yc)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void aspect_flip(GtkWidget *button, dt_iop_module_t *self)
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_orig)
gboolean geometry_record(struct dt_iop_module_t *self, const void *params, dt_geometry_record_t *record)
static void transform(float *x, float *o, const float *m, const float t_h, const float t_v)
gboolean has_defaults(struct dt_iop_module_t *self)
const char * deprecated_msg()
int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
static void gui_draw_sym(cairo_t *cr, float x, float y, float scale, gboolean active)
static void inv_matrix(float *m, float *inv_m)
void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
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 key_swap_callback(GtkAccelGroup *accel_group, GObject *acceleratable, guint keyval, GdkModifierType modifier, gpointer d)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_conf_string_entry_free(gpointer data)
Free one dt_conf_string_entry_t. Shaped as a GDestroyNotify so it can be handed to g_slist_free_full(...
void dt_conf_set_int(const char *name, int val)
GSList * dt_conf_all_string_entries(const char *dir)
Every key under dir, as a list of copies.
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
gboolean dt_image_get_usercrop_oriented(const dt_image_t *img, const dt_image_orientation_t orientation, dt_boundingbox_t box)
dt_image_orientation_t dt_image_get_effective_orientation(const dt_image_t *img)
void dt_control_log(const char *msg,...)
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
void dt_control_hinter_message(const struct dt_control_t *s, const char *message)
gboolean dt_control_button_down(int which)
Is mouse button which currently held down?
#define dt_control_queue_cursor(cursor)
struct dt_control_t * dt_control_get_global(void)
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_resync_history_all(dev)
int32_t dt_dev_roi_request_preview_height(const dt_develop_t *dev)
int32_t dt_dev_roi_request_preview_width(const dt_develop_t *dev)
float dt_dev_viewport_scaling(const dt_develop_t *dev)
void dt_dev_get_processed_size(const dt_develop_t *dev, int *procw, int *proch)
void dt_dev_coordinates_preview_abs_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
int dt_dev_get_thumbnail_size(dt_develop_t *dev)
int dt_dev_distort_backtransform_gui(dt_develop_t *dev, const double iop_order, const int transf_direction, float *points, size_t points_count)
The inverse of dt_dev_distort_transform_gui(), same rules.
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
void dt_dev_coordinates_image_norm_to_preview_abs(dt_develop_t *dev, float *points, size_t num_points)
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.
int dt_dev_distort_transform_gui(dt_develop_t *dev, const double iop_order, const int transf_direction, float *points, size_t points_count)
The GUI's bounded transform folds, composed by the geometry service.
gboolean dt_dev_pixelpipe_has_preview_output(const dt_develop_t *dev, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi)
void dt_dev_coordinates_widget_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Coordinate conversion helpers between widget, normalized image, and absolute image spaces.
@ DT_DEV_TRANSFORM_DIR_FORW_INCL
@ DT_DEV_TRANSFORM_DIR_FORW_EXCL
static void dt_draw_set_color_overlay(cairo_t *cr, gboolean bright, double alpha)
static void dt_gui_draw_rounded_rectangle(cairo_t *cr, float width, float height, float x, float y)
Where things are on the image, answered without a pipeline.
void dt_guides_draw(cairo_t *cr, const float left, const float top, const float width, const float height, const float zoom_scale)
float dt_boundingbox_t[4]
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)
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)
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
@ IOP_FLAGS_TILING_FULL_ROI
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__ void dt_interpolation_compute_pixel4c(const struct dt_interpolation *itor, const float *in, float *out, const float x, const float y, const int width, const int height, const int linestride)
__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_USERPREF_WARP
_lib_location_type_t type
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...
static void mul_mat_vec_2(const float *m, const float *p, float *o)
#define CLAMPF(a, mn, mx)
#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.
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.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
GtkNotebook * dt_ui_notebook_new()
#define __OMP_DECLARE_SIMD__(...)
#define __OMP_PARALLEL_FOR__(...)
#define __OMP_PARALLEL_FOR_SIMD__(...)
#define DT_PIXELPIPE_CACHE_HASH_INVALID
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
This signal is raised when develop preview pipe process is finished no param, no returned value.
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
const float uint32_t state[4]
const float const int flip
unsigned __int64 uint64_t
One key/value pair handed back by dt_conf_all_string_entries().
struct dt_iop_module_t *void * data
struct dt_iop_module_t * gui_module
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.
void(* map_size)(const void *data, const dt_iop_roi_t *const in, dt_iop_roi_t *out)
Full-resolution input rect -> output rect. Mirrors modify_roi_out() at scale 1.
GtkWidget * keystone_type
uint64_t clip_max_pipe_hash
GtkWidget * aspect_presets
dt_iop_params_t * default_params
struct dt_iop_module_gui_t * gui
struct dt_develop_t * dev
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__
typedef double((*spd)(unsigned long int wavelength, double TempK))