97#define DT_GUI_CURVE_EDITOR_INSET DT_PIXEL_APPLY_DPI(1)
98#define DT_GUI_CURVE_INFL .3f
100#define DT_IOP_TONECURVE_RES 256
101#define DT_IOP_TONECURVE_MAXNODES 20
242 return _(
"tone curve");
263 _(
"corrective and creative"),
264 _(
"linear or non-linear, Lab, display-referred"),
265 _(
"non-linear, Lab"),
266 _(
"non-linear, Lab, display-referred"));
270 void *new_params,
const int new_version)
272 if(old_version == 1 && new_version == 5)
280 { { 0.0, 0.0 }, { 0.5, 0.5 }, { 1.0, 1.0 } },
281 { { 0.0, 0.0 }, { 0.5, 0.5 }, { 1.0, 1.0 } } },
289 n->tonecurve_nodes[
ch_L] = 6;
291 n->tonecurve_autoscale_ab = 1;
293 n->tonecurve_unbound_ab = 0;
294 n->preserve_colors = 0;
297 else if(old_version == 2 && new_version == 5)
302 else if(old_version == 3 && new_version == 5)
307 memcpy(
n->tonecurve, o->
tonecurve,
sizeof(
n->tonecurve));
312 n->tonecurve_unbound_ab = 0;
313 n->preserve_colors = 0;
316 else if(old_version == 4 && new_version == 5)
322 n->preserve_colors = 0;
337 const float xm_L = 1.0f /
d->unbounded_coeffs_L[0];
338 const float xm_ar = 1.0f /
d->unbounded_coeffs_ab[0];
339 const float xm_al = 1.0f - 1.0f /
d->unbounded_coeffs_ab[3];
340 const float xm_br = 1.0f /
d->unbounded_coeffs_ab[6];
341 const float xm_bl = 1.0f - 1.0f /
d->unbounded_coeffs_ab[9];
342 const float low_approximation =
d->table[0][(int)(0.01f * 0x10000ul)];
344 const size_t npixels = (size_t)roi_out->
width * roi_out->
height;
345 const int autoscale_ab =
d->autoscale_ab;
346 const int unbound_ab =
d->unbound_ab;
348 const float *
const restrict in = (
float*)
i;
349 float *
const restrict
out = (
float*)o;
351 for(
int k = 0;
k < 4*npixels;
k += 4)
353 const float L_in = in[
k] / 100.0f;
355 out[
k+0] = (L_in < xm_L) ?
d->table[
ch_L][CLAMP((
int)(L_in * 0x10000ul), 0, 0xffff)]
360 const float a_in = (in[
k+1] + 128.0f) / 256.0f;
361 const float b_in = (in[
k+2] + 128.0f) / 256.0f;
366 out[
k+1] =
d->table[
ch_a][CLAMP((
int)(a_in * 0x10000ul), 0, 0xffff)];
367 out[
k+2] =
d->table[
ch_b][CLAMP((
int)(b_in * 0x10000ul), 0, 0xffff)];
373 out[
k+1] = (a_in > xm_ar)
375 : ((a_in < xm_al) ?
dt_iop_eval_exp(
d->unbounded_coeffs_ab + 3, 1.0f - a_in)
376 :
d->table[
ch_a][CLAMP((
int)(a_in * 0x10000ul), 0, 0xffff)]);
377 out[
k+2] = (b_in > xm_br)
379 : ((b_in < xm_bl) ?
dt_iop_eval_exp(
d->unbounded_coeffs_ab + 9, 1.0f - b_in)
380 :
d->table[
ch_b][CLAMP((
int)(b_in * 0x10000ul), 0, 0xffff)]);
393 out[
k+1] = in[
k+1] * low_approximation;
394 out[
k+2] = in[
k+2] * low_approximation;
402 XYZ[c] = (
XYZ[c] < xm_L) ?
d->table[
ch_L][CLAMP((
int)(
XYZ[c] * 0x10000ul), 0, 0xffff)]
409 dt_Lab_to_prophotorgb(in +
k,
rgb);
412 for(
int c = 0; c < 3; c++)
414 rgb[c] = (
rgb[c] < xm_L) ?
d->table[
ch_L][CLAMP((
int)(
rgb[c] * 0x10000ul), 0, 0xffff)]
424 const float curve_lum = (lum < xm_L)
425 ?
d->table[
ch_L][CLAMP((
int)(lum * 0x10000ul), 0, 0xffff)]
427 ratio = curve_lum / lum;
429 for(
size_t c = 0; c < 3; c++)
431 rgb[c] = (ratio *
rgb[c]);
434 dt_prophotorgb_to_Lab(
rgb,
out +
k);
456 {
"Nikon D750",
"NIKON CORPORATION",
"NIKON D750", 0, FLT_MAX, {{{{0.000000, 0.000000}, {0.083508, 0.073677}, {0.212191, 0.274799}, {0.397095, 0.594035}, {0.495025, 0.714660}, {0.683565, 0.878550}, {0.854059, 0.950927}, {1.000000, 1.000000}}, {{0.000000, 0.000000}, {0.125000, 0.125000}, {0.250000, 0.250000}, {0.375000, 0.375000}, {0.500000, 0.500000}, {0.625000, 0.625000}, {0.750000, 0.750000}, {0.875000, 0.875000}}, {{0.000000, 0.000000}, {0.125000, 0.125000}, {0.250000, 0.250000}, {0.375000, 0.375000}, {0.500000, 0.500000}, {0.625000, 0.625000}, {0.750000, 0.750000}, {0.875000, 0.875000} }}, {8, 8, 8}, {2, 2, 2}, 1, 0, 0}},
458 {
"NIKON D5100",
"NIKON CORPORATION",
"NIKON D5100", 0, FLT_MAX, {{{{0.000000, 0.000000}, {0.000957, 0.000176}, {0.002423, 0.000798}, {0.005893, 0.003685}, {0.013219, 0.006619}, {0.023372, 0.011954}, {0.037580, 0.017817}, {0.069695, 0.035353}, {0.077276, 0.040315}, {0.123707, 0.082707}, {0.145249, 0.112105}, {0.189168, 0.186135}, {0.219576, 0.243677}, {0.290201, 0.385251}, {0.428150, 0.613355}, {0.506199, 0.700256}, {0.622833, 0.805488}, {0.702763, 0.870959}, {0.935053, 0.990139}, {1.000000, 1.000000}}, {{0.000000, 0.000000}, {0.050000, 0.050000}, {0.100000, 0.100000}, {0.150000, 0.150000}, {0.200000, 0.200000}, {0.250000, 0.250000}, {0.300000, 0.300000}, {0.350000, 0.350000}, {0.400000, 0.400000}, {0.450000, 0.450000}, {0.500000, 0.500000}, {0.550000, 0.550000}, {0.600000, 0.600000}, {0.650000, 0.650000}, {0.700000, 0.700000}, {0.750000, 0.750000}, {0.800000, 0.800000}, {0.850000, 0.850000}, {0.900000, 0.900000}, {0.950000, 0.950000}}, {{0.000000, 0.000000}, {0.050000, 0.050000}, {0.100000, 0.100000}, {0.150000, 0.150000}, {0.200000, 0.200000}, {0.250000, 0.250000}, {0.300000, 0.300000}, {0.350000, 0.350000}, {0.400000, 0.400000}, {0.450000, 0.450000}, {0.500000, 0.500000}, {0.550000, 0.550000}, {0.600000, 0.600000}, {0.650000, 0.650000}, {0.700000, 0.700000}, {0.750000, 0.750000}, {0.800000, 0.800000}, {0.850000, 0.850000}, {0.900000, 0.900000}, {0.950000, 0.950000}}}, {20, 20, 20}, {2, 2, 2}, 1, 0, 0}},
460 {
"Nikon D7000",
"NIKON CORPORATION",
"NIKON D7000", 0, FLT_MAX, {{{{0.000000, 0.000000}, {0.110633, 0.111192}, {0.209771, 0.286963}, {0.355888, 0.561236}, {0.454987, 0.673098}, {0.769212, 0.920485}, {0.800468, 0.933428}, {1.000000, 1.000000}}, {{0.000000, 0.000000}, {0.125000, 0.125000}, {0.250000, 0.250000}, {0.375000, 0.375000}, {0.500000, 0.500000}, {0.625000, 0.625000}, {0.750000, 0.750000}, {0.875000, 0.875000}}, {{0.000000, 0.000000}, {0.125000, 0.125000}, {0.250000, 0.250000}, {0.375000, 0.375000}, {0.500000, 0.500000}, {0.625000, 0.625000}, {0.750000, 0.750000}, {0.875000, 0.875000}}}, {8, 8, 8}, {2, 2, 2}, 1, 0, 0}},
462 {
"Nikon D7200",
"NIKON CORPORATION",
"NIKON D7200", 0, FLT_MAX, {{{{0.000000, 0.000000}, {0.000618, 0.003286}, {0.001639, 0.003705}, {0.005227, 0.005101}, {0.013299, 0.011192}, {0.016048, 0.013130}, {0.037941, 0.027014}, {0.058195, 0.041339}, {0.086531, 0.069088}, {0.116679, 0.107283}, {0.155629, 0.159422}, {0.205477, 0.246265}, {0.225923, 0.287343}, {0.348056, 0.509104}, {0.360629, 0.534732}, {0.507562, 0.762089}, {0.606899, 0.865692}, {0.734828, 0.947468}, {0.895488, 0.992021}, {1.000000, 1.000000}}, {{0.000000, 0.000000}, {0.050000, 0.050000}, {0.100000, 0.100000}, {0.150000, 0.150000}, {0.200000, 0.200000}, {0.250000, 0.250000}, {0.300000, 0.300000}, {0.350000, 0.350000}, {0.400000, 0.400000}, {0.450000, 0.450000}, {0.500000, 0.500000}, {0.550000, 0.550000}, {0.600000, 0.600000}, {0.650000, 0.650000}, {0.700000, 0.700000}, {0.750000, 0.750000}, {0.800000, 0.800000}, {0.850000, 0.850000}, {0.900000, 0.900000}, {0.950000, 0.950000}}, {{0.000000, 0.000000}, {0.050000, 0.050000}, {0.100000, 0.100000}, {0.150000, 0.150000}, {0.200000, 0.200000}, {0.250000, 0.250000}, {0.300000, 0.300000}, {0.350000, 0.350000}, {0.400000, 0.400000}, {0.450000, 0.450000}, {0.500000, 0.500000}, {0.550000, 0.550000}, {0.600000, 0.600000}, {0.650000, 0.650000}, {0.700000, 0.700000}, {0.750000, 0.750000}, {0.800000, 0.800000}, {0.850000, 0.850000}, {0.900000, 0.900000}, {0.950000, 0.950000}}}, {20, 20, 20}, {2, 2, 2}, 1, 0, 0}},
464 {
"NIKON D7500",
"NIKON CORPORATION",
"NIKON D7500", 0, FLT_MAX, {{{{0.000000, 0.000000}, {0.000421, 0.003412}, {0.003775, 0.004001}, {0.013762, 0.008704}, {0.016698, 0.010230}, {0.034965, 0.018732}, {0.087311, 0.049808}, {0.101389, 0.060789}, {0.166845, 0.145269}, {0.230944, 0.271288}, {0.333399, 0.502609}, {0.353207, 0.542549}, {0.550014, 0.819535}, {0.731749, 0.944033}, {0.783283, 0.960546}, {1.000000, 1.000000}}, {{0.000000, 0.000000}, {0.062500, 0.062500}, {0.125000, 0.125000}, {0.187500, 0.187500}, {0.250000, 0.250000}, {0.312500, 0.312500}, {0.375000, 0.375000}, {0.437500, 0.437500}, {0.500000, 0.500000}, {0.562500, 0.562500}, {0.625000, 0.625000}, {0.687500, 0.687500}, {0.750000, 0.750000}, {0.812500, 0.812500}, {0.875000, 0.875000}, {0.937500, 0.937500}}, {{0.000000, 0.000000}, {0.062500, 0.062500}, {0.125000, 0.125000}, {0.187500, 0.187500}, {0.250000, 0.250000}, {0.312500, 0.312500}, {0.375000, 0.375000}, {0.437500, 0.437500}, {0.500000, 0.500000}, {0.562500, 0.562500}, {0.625000, 0.625000}, {0.687500, 0.687500}, {0.750000, 0.750000}, {0.812500, 0.812500}, {0.875000, 0.875000}, {0.937500, 0.937500}}}, {16, 16, 16}, {2, 2, 2}, 1, 0, 0}},
466 {
"Nikon D90",
"NIKON CORPORATION",
"NIKON D90", 0, FLT_MAX, {{{{0.000000, 0.000000}, {0.002915, 0.006453}, {0.023324, 0.021601}, {0.078717, 0.074963}, {0.186589, 0.242230}, {0.364432, 0.544956}, {0.629738, 0.814127}, {1.000000, 1.000000}}, {{0.000000, 0.000000}, {0.125000, 0.125000}, {0.250000, 0.250000}, {0.375000, 0.375000}, {0.500000, 0.500000}, {0.625000, 0.625000}, {0.750000, 0.750000}, {0.875000, 0.875000}}, {{0.000000, 0.000000}, {0.125000, 0.125000}, {0.250000, 0.250000}, {0.375000, 0.375000}, {0.500000, 0.500000}, {0.625000, 0.625000}, {0.750000, 0.750000}, {0.875000, 0.875000}}}, {8, 8, 8}, {2, 2, 2}, 1, 0, 0}},
468 {
"Olympus OM-D E-M10 II",
"OLYMPUS CORPORATION ",
"E-M10MarkII ", 0, FLT_MAX, {{{{0.000000, 0.000000}, {0.004036, 0.000809}, {0.015047, 0.009425}, {0.051948, 0.042053}, {0.071777, 0.066635}, {0.090018, 0.086722}, {0.110197, 0.118773}, {0.145817, 0.171861}, {0.207476, 0.278652}, {0.266832, 0.402823}, {0.428061, 0.696319}, {0.559728, 0.847113}, {0.943576, 0.993482}, {1.000000, 1.000000}}, {{0.000000, 0.000000}, {0.071429, 0.071429}, {0.142857, 0.142857}, {0.214286, 0.214286}, {0.285714, 0.285714}, {0.357143, 0.357143}, {0.428571, 0.428571}, {0.500000, 0.500000}, {0.571429, 0.571429}, {0.642857, 0.642857}, {0.714286, 0.714286}, {0.785714, 0.785714}, {0.857143, 0.857143}, {0.928571, 0.928571}}, {{0.000000, 0.000000}, {0.071429, 0.071429}, {0.142857, 0.142857}, {0.214286, 0.214286}, {0.285714, 0.285714}, {0.357143, 0.357143}, {0.428571, 0.428571}, {0.500000, 0.500000}, {0.571429, 0.571429}, {0.642857, 0.642857}, {0.714286, 0.714286}, {0.785714, 0.785714}, {0.857143, 0.857143}, {0.928571, 0.928571}}}, {14, 14, 14}, {2, 2, 2}, 1, 0, 0}},
475 memset(&
p, 0,
sizeof(
p));
476 p.tonecurve_nodes[
ch_L] = 6;
477 p.tonecurve_nodes[
ch_a] = 7;
478 p.tonecurve_nodes[
ch_b] = 7;
482 p.tonecurve_preset = 0;
484 p.tonecurve_unbound_ab = 1;
486 float linear_ab[7] = { 0.0, 0.08, 0.3, 0.5, 0.7, 0.92, 1.0 };
489 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_a][
k].x = linear_ab[
k];
490 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_a][
k].y = linear_ab[
k];
491 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_b][
k].x = linear_ab[
k];
492 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_b][
k].y = linear_ab[
k];
495 p.tonecurve[
ch_L][0].x = 0.000000;
496 p.tonecurve[
ch_L][1].x = 0.003862;
497 p.tonecurve[
ch_L][2].x = 0.076613;
498 p.tonecurve[
ch_L][3].x = 0.169355;
499 p.tonecurve[
ch_L][4].x = 0.774194;
500 p.tonecurve[
ch_L][5].x = 1.000000;
501 p.tonecurve[
ch_L][0].y = 0.000000;
502 p.tonecurve[
ch_L][1].y = 0.007782;
503 p.tonecurve[
ch_L][2].y = 0.156182;
504 p.tonecurve[
ch_L][3].y = 0.290352;
505 p.tonecurve[
ch_L][4].y = 0.773852;
506 p.tonecurve[
ch_L][5].y = 1.000000;
510 p.tonecurve_nodes[
ch_L] = 7;
511 float linear_L[7] = { 0.0, 0.08, 0.17, 0.50, 0.83, 0.92, 1.0 };
514 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].x = linear_L[
k];
515 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].y = linear_L[
k];
520 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].x = linear_L[
k];
521 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].y = linear_L[
k];
522 p.tonecurve[
ch_L][1].y -= 0.020;
523 p.tonecurve[
ch_L][2].y -= 0.030;
524 p.tonecurve[
ch_L][4].y += 0.030;
525 p.tonecurve[
ch_L][5].y += 0.020;
529 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].x = linear_L[
k];
530 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].y = linear_L[
k];
531 p.tonecurve[
ch_L][1].y -= 0.040;
532 p.tonecurve[
ch_L][2].y -= 0.060;
533 p.tonecurve[
ch_L][4].y += 0.060;
534 p.tonecurve[
ch_L][5].y += 0.040;
539 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].x = linear_L[
k];
540 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].y = linear_L[
k];
541 p.tonecurve[
ch_L][1].y -= 0.020;
542 p.tonecurve[
ch_L][2].y -= 0.030;
543 p.tonecurve[
ch_L][4].y += 0.030;
544 p.tonecurve[
ch_L][5].y += 0.020;
545 for(
int k = 1;
k < 6;
k++)
p.tonecurve[
ch_L][
k].x = powf(
p.tonecurve[
ch_L][
k].x, 2.2f);
546 for(
int k = 1;
k < 6;
k++)
p.tonecurve[
ch_L][
k].y = powf(
p.tonecurve[
ch_L][
k].y, 2.2f);
550 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].x = linear_L[
k];
551 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].y = linear_L[
k];
552 p.tonecurve[
ch_L][1].y -= 0.040;
553 p.tonecurve[
ch_L][2].y -= 0.060;
554 p.tonecurve[
ch_L][4].y += 0.060;
555 p.tonecurve[
ch_L][5].y += 0.040;
556 for(
int k = 1;
k < 6;
k++)
p.tonecurve[
ch_L][
k].x = powf(
p.tonecurve[
ch_L][
k].x, 2.2f);
557 for(
int k = 1;
k < 6;
k++)
p.tonecurve[
ch_L][
k].y = powf(
p.tonecurve[
ch_L][
k].y, 2.2f);
565 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].x = linear_L[
k];
566 for(
int k = 0;
k < 7;
k++)
p.tonecurve[
ch_L][
k].y = linear_L[
k];
569 for(
int k = 1;
k < 6;
k++)
p.tonecurve[
ch_L][
k].y = powf(linear_L[
k], 2.0f);
574 for(
int k = 1;
k < 6;
k++)
p.tonecurve[
ch_L][
k].y = powf(linear_L[
k], 0.5f);
579 for(
int k = 1;
k < 6;
k++)
p.tonecurve[
ch_L][
k].y = logf(linear_L[
k] + 1.0f) / logf(2.0f);
584 for(
int k = 1;
k < 6;
k++)
p.tonecurve[
ch_L][
k].y = powf(2.0f, linear_L[
k]) - 1.0f;
624 if(
d->curve_type[
ch] !=
p->tonecurve_type[
ch] ||
d->curve_nodes[
ch] !=
p->tonecurve_nodes[
ch])
628 d->curve_nodes[
ch] =
p->tonecurve_nodes[
ch];
629 d->curve_type[
ch] =
p->tonecurve_type[
ch];
630 for(
int k = 0;
k <
p->tonecurve_nodes[
ch];
k++)
635 for(
int k = 0;
k <
p->tonecurve_nodes[
ch];
k++)
640 for(
int k = 0;
k < 0x10000;
k++)
d->table[
ch_L][
k] *= 100.0f;
641 for(
int k = 0;
k < 0x10000;
k++)
d->table[
ch_a][
k] =
d->table[
ch_a][
k] * 256.0f - 128.0f;
642 for(
int k = 0;
k < 0x10000;
k++)
d->table[
ch_b][
k] =
d->table[
ch_b][
k] * 256.0f - 128.0f;
648 for(
int k=0;
k<0x10000;
k++)
653 Lab[0] =
d->table[
ch_L][CLAMP((
int)(
Lab[0]/100.0f * 0x10000), 0, 0xffff)];
661 for(
int k=0;
k<0x10000;
k++)
665 dt_prophotorgb_to_Lab(
rgb,
Lab);
666 Lab[0] =
d->table[
ch_L][CLAMP((
int)(
Lab[0]/100.0f * 0x10000), 0, 0xffff)];
667 dt_Lab_to_prophotorgb(
Lab,
rgb);
672 d->autoscale_ab =
p->tonecurve_autoscale_ab;
673 d->unbound_ab =
p->tonecurve_unbound_ab;
674 d->preserve_colors =
p->preserve_colors;
677 const float xm_L =
p->tonecurve[
ch_L][
p->tonecurve_nodes[
ch_L] - 1].x;
678 const float x_L[4] = { 0.7f * xm_L, 0.8f * xm_L, 0.9f * xm_L, 1.0f * xm_L };
679 const float y_L[4] = {
d->table[
ch_L][CLAMP((
int)(x_L[0] * 0x10000ul), 0, 0xffff)],
680 d->table[
ch_L][CLAMP((
int)(x_L[1] * 0x10000ul), 0, 0xffff)],
681 d->table[
ch_L][CLAMP((
int)(x_L[2] * 0x10000ul), 0, 0xffff)],
682 d->table[
ch_L][CLAMP((
int)(x_L[3] * 0x10000ul), 0, 0xffff)] };
686 const float xm_ar =
p->tonecurve[
ch_a][
p->tonecurve_nodes[
ch_a] - 1].x;
687 const float x_ar[4] = { 0.7f * xm_ar, 0.8f * xm_ar, 0.9f * xm_ar, 1.0f * xm_ar };
688 const float y_ar[4] = {
d->table[
ch_a][CLAMP((
int)(x_ar[0] * 0x10000ul), 0, 0xffff)],
689 d->table[
ch_a][CLAMP((
int)(x_ar[1] * 0x10000ul), 0, 0xffff)],
690 d->table[
ch_a][CLAMP((
int)(x_ar[2] * 0x10000ul), 0, 0xffff)],
691 d->table[
ch_a][CLAMP((
int)(x_ar[3] * 0x10000ul), 0, 0xffff)] };
695 const float xm_al = 1.0f -
p->tonecurve[
ch_a][0].x;
696 const float x_al[4] = { 0.7f * xm_al, 0.8f * xm_al, 0.9f * xm_al, 1.0f * xm_al };
697 const float y_al[4] = {
d->table[
ch_a][CLAMP((
int)((1.0f - x_al[0]) * 0x10000ul), 0, 0xffff)],
698 d->table[
ch_a][CLAMP((
int)((1.0f - x_al[1]) * 0x10000ul), 0, 0xffff)],
699 d->table[
ch_a][CLAMP((
int)((1.0f - x_al[2]) * 0x10000ul), 0, 0xffff)],
700 d->table[
ch_a][CLAMP((
int)((1.0f - x_al[3]) * 0x10000ul), 0, 0xffff)] };
704 const float xm_br =
p->tonecurve[
ch_b][
p->tonecurve_nodes[
ch_b] - 1].x;
705 const float x_br[4] = { 0.7f * xm_br, 0.8f * xm_br, 0.9f * xm_br, 1.0f * xm_br };
706 const float y_br[4] = {
d->table[
ch_b][CLAMP((
int)(x_br[0] * 0x10000ul), 0, 0xffff)],
707 d->table[
ch_b][CLAMP((
int)(x_br[1] * 0x10000ul), 0, 0xffff)],
708 d->table[
ch_b][CLAMP((
int)(x_br[2] * 0x10000ul), 0, 0xffff)],
709 d->table[
ch_b][CLAMP((
int)(x_br[3] * 0x10000ul), 0, 0xffff)] };
713 const float xm_bl = 1.0f -
p->tonecurve[
ch_b][0].x;
714 const float x_bl[4] = { 0.7f * xm_bl, 0.8f * xm_bl, 0.9f * xm_bl, 1.0f * xm_bl };
715 const float y_bl[4] = {
d->table[
ch_b][CLAMP((
int)((1.0f - x_bl[0]) * 0x10000ul), 0, 0xffff)],
716 d->table[
ch_b][CLAMP((
int)((1.0f - x_bl[1]) * 0x10000ul), 0, 0xffff)],
717 d->table[
ch_b][CLAMP((
int)((1.0f - x_bl[2]) * 0x10000ul), 0, 0xffff)],
718 d->table[
ch_b][CLAMP((
int)((1.0f - x_bl[3]) * 0x10000ul), 0, 0xffff)] };
734 piece->
data = (
void *)
d;
747 for(
int k = 0;
k < 0x10000;
k++)
d->table[
ch_L][
k] = 100.0f *
k / 0x10000;
748 for(
int k = 0;
k < 0x10000;
k++)
d->table[
ch_a][
k] = 256.0f *
k / 0x10000 - 128.0f;
749 for(
int k = 0;
k < 0x10000;
k++)
d->table[
ch_b][
k] = 256.0f *
k / 0x10000 - 128.0f;
772 gtk_widget_queue_draw(self->
widget);
785 gtk_widget_queue_draw(self->
widget);
792 module->request_histogram |= (DT_REQUEST_ON);
797 d->tonecurve_nodes[1] =
798 d->tonecurve_nodes[2] = 3;
799 d->tonecurve[0][1].x =
d->tonecurve[0][1].y =
800 d->tonecurve[1][2].x =
d->tonecurve[1][2].y =
801 d->tonecurve[2][2].x =
d->tonecurve[2][2].y = 1.0f;
802 d->tonecurve[1][1].x =
d->tonecurve[1][1].y =
803 d->tonecurve[2][1].x =
d->tonecurve[2][1].y = 0.5f;
811 for(
int k=0;
k<3;
k++)
830 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
838 if(w ==
g->autoscale_ab)
841 gtk_notebook_set_current_page(GTK_NOTEBOOK(
g->channel_tabs),
ch_L);
843 gtk_notebook_set_show_tabs(
g->channel_tabs,
p->tonecurve_autoscale_ab ==
DT_S_SCALE_MANUAL);
846 gtk_widget_queue_draw(self->
widget);
860 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
869 gtk_widget_queue_draw(self->
widget);
875 GtkAllocation allocation;
876 gtk_widget_get_allocation(widget, &allocation);
877 r.width = allocation.width;
878 r.height = allocation.width;
879 gtk_widget_get_preferred_size(widget, &
r, NULL);
883static float to_log(
const float x,
const float base,
const int ch,
const int semilog,
const int is_ordinate)
886 if(base > 0.0f &&
ch ==
ch_L)
888 if (semilog == 1 && is_ordinate == 1)
893 else if (semilog == -1 && is_ordinate == 0)
900 return logf(
x * base + 1.0f) / logf(base + 1.0f);
909static float to_lin(
const float x,
const float base,
const int ch,
const int semilog,
const int is_ordinate)
912 if(base > 0.0f &&
ch ==
ch_L)
914 if (semilog == 1 && is_ordinate == 1)
919 else if (semilog == -1 && is_ordinate == 0)
926 return (powf(base + 1.0f,
x) - 1.0f) / base;
940 for(
int k=0;
k<3;
k++)
956 int nodes =
p->tonecurve_nodes[
ch];
958 int autoscale_ab =
p->tonecurve_autoscale_ab;
963 if(nodes <= 2)
return;
970 if((c->selected > 0 && (
tonecurve[c->selected - 1].
x >= mx))
971 || (c->selected < nodes - 1 && (
tonecurve[c->selected + 1].
x <= mx)))
973 for(
int k = c->selected;
k < nodes - 1;
k++)
979 p->tonecurve_nodes[
ch]--;
996 gtk_widget_queue_draw(widget);
1002#define TONECURVE_DEFAULT_STEP (0.001f)
1010 int ch = c->channel;
1011 int autoscale_ab =
p->tonecurve_autoscale_ab;
1016 if(c->selected < 0)
return TRUE;
1034 int ch = c->channel;
1035 int autoscale_ab =
p->tonecurve_autoscale_ab;
1040 if(c->selected < 0)
return FALSE;
1044 float dx = 0.0f, dy = 0.0f;
1045 if(
key == GDK_KEY_Up)
1050 else if(
key == GDK_KEY_Down)
1055 else if(
key == GDK_KEY_Right)
1060 else if(
key == GDK_KEY_Left)
1066 if(!handled)
return FALSE;
1071#undef TONECURVE_DEFAULT_STEP
1081 c->minmax_curve_nodes[
ch] =
p->tonecurve_nodes[
ch];
1082 c->minmax_curve_type[
ch] =
p->tonecurve_type[
ch];
1083 for(
int k = 0;
k <
p->tonecurve_nodes[
ch];
k++)
1088 c->mouse_x = c->mouse_y = -1.0;
1095 gtk_widget_set_tooltip_text(c->autoscale_ab, _(
"if set to auto, a and b curves have no effect and are "
1096 "not displayed. chroma values (a and b) of each pixel are "
1097 "then adjusted based on L curve data. auto XYZ is similar "
1098 "but applies the saturation changes in XYZ space."));
1105 g_signal_connect(G_OBJECT(c->channel_tabs),
"switch_page", G_CALLBACK(
tab_switch), self);
1106 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(c->channel_tabs),
TRUE,
TRUE, 0);
1107 gtk_box_pack_start(GTK_BOX(hbox), gtk_grid_new(),
TRUE,
TRUE, 0);
1110 gtk_widget_set_tooltip_text(c->colorpicker, _(
"pick GUI color from image\nctrl+click or right-click to select an area"));
1114 c->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
1115 gtk_widget_set_hexpand(GTK_WIDGET(c->area),
TRUE);
1116 g_object_set_data(G_OBJECT(c->area),
"iop-instance", self);
1117 gtk_box_pack_start(GTK_BOX(self->
widget),
1119 "plugins/darkroom/tonecurve/graphheight", 280, 100),
1126 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1127 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1128 gtk_widget_set_can_focus(GTK_WIDGET(c->area),
TRUE);
1134 g_signal_connect(G_OBJECT(c->area),
"configure-event", G_CALLBACK(
area_resized), self);
1135 g_signal_connect(G_OBJECT(c->area),
"scroll-event", G_CALLBACK(
_scrolled), self);
1148 gtk_box_pack_start(GTK_BOX(self->
widget), c->interpolator ,
TRUE,
TRUE, 0);
1149 gtk_widget_set_tooltip_text(c->interpolator, _(
"change this method if you see oscillations or cusps in the curve\n"
1150 "- cubic spline is better to produce smooth curves but oscillates when nodes are too close\n"
1151 "- centripetal is better to avoids cusps and oscillations with close nodes but is less smooth\n"
1152 "- monotonic is better for accuracy of pure analytical functions (log, gamma, exp)\n"));
1153 g_signal_connect(G_OBJECT(c->interpolator),
"value-changed", G_CALLBACK(
interpolator_callback), self);
1156 gtk_widget_set_tooltip_text(c->preserve_colors, _(
"method to preserve colors when applying contrast"));
1160 gtk_box_pack_start(GTK_BOX(self->
widget), c->logbase ,
TRUE,
TRUE, 0);
1161 g_signal_connect(G_OBJECT(c->logbase),
"value-changed", G_CALLBACK(
logbase_callback), self);
1163 c->sizegroup = GTK_SIZE_GROUP(gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL));
1164 gtk_size_group_add_widget(c->sizegroup, GTK_WIDGET(c->area));
1165 gtk_size_group_add_widget(c->sizegroup, GTK_WIDGET(c->channel_tabs));
1172 g_object_unref(c->sizegroup);
1183 gtk_widget_queue_draw(widget);
1189 gtk_widget_queue_draw(widget);
1195 out[0] = CLAMP(in[0] / 100.0f, 0.0f, 1.0f);
1196 out[1] = CLAMP((in[1] + 128.0f) / 256.0f, 0.0f, 1.0f);
1197 out[2] = CLAMP((in[2] + 128.0f) / 256.0f, 0.0f, 1.0f);
1207 int ch = c->channel;
1208 int nodes =
p->tonecurve_nodes[
ch];
1211 if(c->minmax_curve_type[
ch] !=
p->tonecurve_type[
ch] || c->minmax_curve_nodes[
ch] !=
p->tonecurve_nodes[
ch])
1215 c->minmax_curve_nodes[
ch] =
p->tonecurve_nodes[
ch];
1216 c->minmax_curve_type[
ch] =
p->tonecurve_type[
ch];
1217 for(
int k = 0;
k <
p->tonecurve_nodes[
ch];
k++)
1222 for(
int k = 0;
k <
p->tonecurve_nodes[
ch];
k++)
1231 const float x[4] = { 0.7f * xm, 0.8f * xm, 0.9f * xm, 1.0f * xm };
1240 GtkAllocation allocation;
1241 gtk_widget_get_allocation(widget, &allocation);
1242 int width = allocation.width,
height = allocation.height;
1244 cairo_t *cr = cairo_create(cst);
1246 cairo_translate(cr, inset, inset);
1255 cairo_stroke_preserve(cr);
1259 cairo_set_source_rgb(cr, .3, .3, .3);
1269 const float origin[3][3] = { { 0.0f, 0.0f, 0.0f },
1270 { 0.0f, 231.0f/255.0f, 181.0f/255.0f },
1271 { 0.0f, 30.0f/255.0f, 195.0f/255.0f}};
1273 const float destin[3][3] = { { 1.0f, 1.0f, 1.0f },
1274 { 1.0f, 0.0f, 192.0f/255.0f } ,
1275 { 215.0f/255.0f, 182.0f/255.0f, 0.0f}};
1283 const float midgrey =
to_log(0.45f, c->loglogscale,
ch, c->semilog, 0);
1285 const float middle[3][3] = { { midgrey, midgrey, midgrey },
1286 { 0.67f, 0.67f, 0.67f},
1287 { 0.67f, 0.67f, 0.67f}};
1289 const float opacities[3] = { 0.5f, 0.5f, 0.5f};
1291 cairo_pattern_t *pat;
1292 pat = cairo_pattern_create_linear (
height, 0.0, 0.0,
width);
1293 cairo_pattern_add_color_stop_rgba (pat, 1, origin[
ch][0], origin[
ch][1], origin[
ch][2], opacities[
ch]);
1294 cairo_pattern_add_color_stop_rgba (pat, 0.5, middle[
ch][0], middle[
ch][1], middle[
ch][2], opacities[
ch]);
1295 cairo_pattern_add_color_stop_rgba (pat, 0, destin[
ch][0], destin[
ch][1], destin[
ch][2], opacities[
ch]);
1296 cairo_set_source (cr, pat);
1298 cairo_pattern_destroy (pat);
1304 if (c->loglogscale > 0.0f &&
ch ==
ch_L )
1306 if (c->semilog == 0)
1310 else if (c->semilog == 1)
1314 else if (c->semilog == -1)
1325 cairo_move_to(cr, 0,
height);
1326 cairo_line_to(cr,
width, 0);
1328 cairo_translate(cr, 0,
height);
1334 float *raw_mean, *raw_min, *raw_max;
1335 float *raw_mean_output;
1337 const gboolean is_linear =
FALSE;
1350 cairo_move_to(cr, 0,
height);
1353 if (
ch ==
ch_L && c->loglogscale > 0.0f)
1364 cairo_move_to(cr, 0,
height);
1366 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(c->colorpicker)))
1380 picker_min[
ch] =
to_log(picker_min[
ch], c->loglogscale,
ch, c->semilog, 0);
1381 picker_max[
ch] =
to_log(picker_max[
ch], c->loglogscale,
ch, c->semilog, 0);
1382 picker_mean[
ch] =
to_log(picker_mean[
ch], c->loglogscale,
ch, c->semilog, 0);
1384 cairo_set_source_rgba(cr, 0.5, 0.7, 0.5, 0.35);
1385 cairo_rectangle(cr,
width * picker_min[
ch], 0,
width * fmax(picker_max[
ch] - picker_min[
ch], 0.0f),
1388 cairo_set_source_rgba(cr, 0.5, 0.7, 0.5, 0.5);
1389 cairo_move_to(cr,
width * picker_mean[
ch], 0);
1395 if(raw_max[0] >= 0.0f)
1398 PangoLayout *layout;
1401 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
1402 pango_font_description_set_absolute_size(desc, PANGO_SCALE);
1403 layout = pango_cairo_create_layout(cr);
1404 pango_layout_set_font_description(layout, desc);
1411 snprintf(text,
sizeof(text),
"100.00 / 100.00 ( +100.00)");
1412 pango_layout_set_text(layout, text, -1);
1413 pango_layout_get_pixel_extents(layout, &ink, NULL);
1414 pango_font_description_set_absolute_size(desc,
width*1.0/ink.width * PANGO_SCALE);
1415 pango_layout_set_font_description(layout, desc);
1417 picker_min[
ch] =
to_log(picker_min[
ch], c->loglogscale,
ch, c->semilog, 0);
1418 picker_max[
ch] =
to_log(picker_max[
ch], c->loglogscale,
ch, c->semilog, 0);
1419 picker_mean[
ch] =
to_log(picker_mean[
ch], c->loglogscale,
ch, c->semilog, 0);
1421 cairo_set_source_rgba(cr, 0.7, 0.5, 0.5, 0.35);
1422 cairo_rectangle(cr,
width * picker_min[
ch], 0,
width * fmax(picker_max[
ch] - picker_min[
ch], 0.0f),
1425 cairo_set_source_rgba(cr, 0.9, 0.7, 0.7, 0.5);
1426 cairo_move_to(cr,
width * picker_mean[
ch], 0);
1430 snprintf(text,
sizeof(text),
"%.1f \342\206\222 %.1f", raw_mean[
ch], raw_mean_output[
ch]);
1434 pango_layout_set_text(layout, text, -1);
1435 pango_layout_get_pixel_extents(layout, &ink, NULL);
1436 cairo_move_to(cr, 0.02f *
width, -0.94 *
height - ink.height - ink.y);
1437 pango_cairo_show_layout(cr, layout);
1439 pango_font_description_free(desc);
1440 g_object_unref(layout);
1464 const float x =
to_log(xx, c->loglogscale,
ch, c->semilog, 0),
1465 y =
to_log(yy, c->loglogscale,
ch, c->semilog, 1);
1473 for(
int k = 0;
k < nodes;
k++)
1480 cairo_stroke_preserve(cr);
1486 if(c->selected >= 0)
1489 PangoLayout *layout;
1492 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
1493 pango_font_description_set_absolute_size(desc, PANGO_SCALE);
1494 layout = pango_cairo_create_layout(cr);
1495 pango_layout_set_font_description(layout, desc);
1498 snprintf(text,
sizeof(text),
"100.00 / 100.00 ( +100.00)");
1499 pango_layout_set_text(layout, text, -1);
1500 pango_layout_get_pixel_extents(layout, &ink, NULL);
1501 pango_font_description_set_absolute_size(desc,
width*1.0/ink.width * PANGO_SCALE);
1502 pango_layout_set_font_description(layout, desc);
1504 const float min_scale_value =
ch ==
ch_L ? 0.0f : -128.0f;
1505 const float max_scale_value =
ch ==
ch_L ? 100.0f : 128.0f;
1507 const float x_node_value =
tonecurve[c->selected].
x * (max_scale_value - min_scale_value) + min_scale_value;
1508 const float y_node_value =
tonecurve[c->selected].
y * (max_scale_value - min_scale_value) + min_scale_value;
1509 const float d_node_value = y_node_value - x_node_value;
1510 snprintf(text,
sizeof(text),
"%.1f / %.1f ( %+.1f)", x_node_value, y_node_value, d_node_value);
1513 pango_layout_set_text(layout, text, -1);
1514 pango_layout_get_pixel_extents(layout, &ink, NULL);
1515 cairo_move_to(cr, 0.98f *
width - ink.width - ink.x, -0.02 *
height - ink.height - ink.y);
1516 pango_cairo_show_layout(cr, layout);
1518 pango_font_description_free(desc);
1519 g_object_unref(layout);
1531 cairo_set_source_surface(crf, cst, 0, 0);
1533 cairo_surface_destroy(cst);
1544 for(
int k = 1;
k < *nodes;
k++)
1553 if(selected == -1) selected = *nodes;
1554 for(
int i = *nodes;
i > selected;
i--)
1572 int ch = c->channel;
1573 int nodes =
p->tonecurve_nodes[
ch];
1575 int autoscale_ab =
p->tonecurve_autoscale_ab;
1581 GtkAllocation allocation;
1582 gtk_widget_get_allocation(widget, &allocation);
1583 int height = allocation.height - 2 * inset,
width = allocation.width - 2 * inset;
1584 double old_m_x = c->mouse_x;
1585 double old_m_y = c->mouse_y;
1586 c->mouse_x =
event->x - inset;
1587 c->mouse_y =
event->y - inset;
1589 const float mx = CLAMP(c->mouse_x, 0,
width) /
width;
1590 const float my = 1.0f - CLAMP(c->mouse_y, 0,
height) /
height;
1591 const float linx =
to_lin(mx, c->loglogscale,
ch, c->semilog, 0),
1592 liny =
to_lin(my, c->loglogscale,
ch, c->semilog, 1);
1594 if(event->state & GDK_BUTTON1_MASK)
1597 if(c->selected >= 0)
1600 const float translate_mouse_x = old_m_x /
width -
to_log(
tonecurve[c->selected].
x, c->loglogscale,
ch, c->semilog, 0);
1601 const float translate_mouse_y = 1 - old_m_y /
height -
to_log(
tonecurve[c->selected].
y, c->loglogscale,
ch, c->semilog, 1);
1603 const float dx =
to_lin(c->mouse_x /
width - translate_mouse_x, c->loglogscale,
ch, c->semilog, 0)
1604 -
to_lin(old_m_x /
width - translate_mouse_x, c->loglogscale,
ch, c->semilog, 0);
1605 const float dy =
to_lin(1 - c->mouse_y /
height - translate_mouse_y, c->loglogscale,
ch, c->semilog, 1)
1606 -
to_lin(1 - old_m_y /
height - translate_mouse_y, c->loglogscale,
ch, c->semilog, 1);
1609 else if(nodes < DT_IOP_TONECURVE_MAXNODES && c->selected >= -1)
1622 for(
int k = 0;
k < nodes;
k++)
1633 c->selected = nearest;
1636 if(c->selected >= 0) gtk_widget_grab_focus(widget);
1637 gtk_widget_queue_draw(widget);
1648 int ch = c->channel;
1649 int autoscale_ab =
p->tonecurve_autoscale_ab;
1650 int nodes =
p->tonecurve_nodes[
ch];
1653 if(event->button == 1)
1655 if(event->type == GDK_BUTTON_PRESS &&
dt_modifier_is(event->state, GDK_CONTROL_MASK)
1656 && nodes < DT_IOP_TONECURVE_MAXNODES && c->selected == -1)
1660 GtkAllocation allocation;
1661 gtk_widget_get_allocation(widget, &allocation);
1662 int width = allocation.width - 2 * inset;
1663 c->mouse_x =
event->x - inset;
1664 c->mouse_y =
event->y - inset;
1666 const float mx = CLAMP(c->mouse_x, 0,
width) / (float)
width;
1667 const float linx =
to_lin(mx, c->loglogscale,
ch, c->semilog, 0);
1675 for(
int k = 1;
k < nodes;
k++)
1684 if(selected == -1) selected = nodes;
1687 if(!((selected > 0 && linx -
tonecurve[selected - 1].
x <= 0.025) ||
1688 (selected < nodes &&
tonecurve[selected].
x - linx <= 0.025)))
1693 if(y >= 0.0 && y <= 1.0)
1701 for(
int k = 0;
k < nodes;
k++)
1704 float dist = (y - other_y) * (y - other_y);
1705 if(
dist <
min) c->selected = selected;
1709 gtk_widget_queue_draw(self->
widget);
1714 else if(event->type == GDK_2BUTTON_PRESS)
1720 p->tonecurve_nodes[
ch] =
d->tonecurve_nodes[
ch];
1721 p->tonecurve_type[
ch] =
d->tonecurve_type[
ch];
1722 for(
int k = 0;
k <
d->tonecurve_nodes[
ch];
k++)
1724 p->tonecurve[
ch][
k].x =
d->tonecurve[
ch][
k].x;
1725 p->tonecurve[
ch][
k].y =
d->tonecurve[
ch][
k].y;
1730 gtk_widget_queue_draw(self->
widget);
1740 gtk_widget_queue_draw(self->
widget);
1746 else if(event->button == 3 && c->selected >= 0)
1748 if(c->selected == 0 || c->selected == nodes - 1)
1750 float reset_value = c->selected == 0 ? 0 : 1;
1752 gtk_widget_queue_draw(self->
widget);
1757 for(
int k = c->selected;
k < nodes - 1;
k++)
1764 p->tonecurve_nodes[
ch]--;
1765 gtk_widget_queue_draw(self->
widget);
static double dist(double x1, double y1, double x2, double y2)
float dt_bauhaus_slider_get(GtkWidget *widget)
int dt_bauhaus_combobox_get(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_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
static void set_color(cairo_t *cr, GdkRGBA color)
@ DEVELOP_BLEND_CS_RGB_DISPLAY
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
@ DT_COLOR_PICKER_POINT_AREA
@ DT_LIB_COLORPICKER_STATISTIC_MAX
@ DT_LIB_COLORPICKER_STATISTIC_MIN
@ DT_LIB_COLORPICKER_STATISTIC_MEAN
@ DT_COLORSPACE_PROPHOTO_RGB
static dt_aligned_pixel_t rgb
static const float const float const float min
static dt_aligned_pixel_t XYZ
static dt_aligned_pixel_t Lab
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_control_queue_redraw_widget(GtkWidget *widget)
threadsafe request of redraw of specific widget. Use this function if you need to redraw a specific w...
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
#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 float dt_rgb_norm(const float4 in, const int norm, const int work_profile, constant dt_colorspaces_iccprofile_info_cl_t *profile_info, read_only image2d_t lut)
#define dt_dev_add_history_item(dev, module, enable, redraw)
static void dt_draw_curve_calc_values(dt_draw_curve_t *c, const float min, const float max, const int res, float *x, float *y)
static void dt_draw_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom)
static void dt_draw_semilog_y_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom, const float base)
static float dt_draw_curve_calc_value(dt_draw_curve_t *c, const float x)
static void dt_draw_curve_destroy(dt_draw_curve_t *c)
static void dt_draw_histogram_8_log_base(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel, const gboolean linear, float base_log)
static void dt_draw_curve_set_point(dt_draw_curve_t *c, const int num, const float x, const float y)
static int dt_draw_curve_add_point(dt_draw_curve_t *c, const float x, const float y)
static void dt_draw_semilog_x_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom, const float base)
static void dt_draw_histogram_8(cairo_t *cr, const uint32_t *hist, int32_t channels, int32_t channel, const gboolean linear)
static dt_draw_curve_t * dt_draw_curve_new(const float min, const float max, unsigned int type)
static void dt_draw_loglog_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom, const float base)
static guint dt_keys_mainpad_alternatives(const guint key_val)
Remap keypad keys to usual mainpad ones.
gboolean dt_gui_get_scroll_delta(const GdkEventScroll *event, gdouble *delta)
GtkWidget * dt_ui_resizable_drawing_area(GtkWidget *area, char *config_str, int default_height, int min_height)
Make a self-drawing widget (typically a GtkDrawingArea graph or scope) vertically resizable.
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
GtkNotebook * dt_ui_notebook_new()
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
void dt_gui_presets_update_filter(const char *name, dt_dev_operation_t op, const int32_t version, const int filter)
void dt_gui_presets_update_ldr(const char *name, dt_dev_operation_t op, const int32_t version, const int ldrflag)
void dt_gui_presets_update_iso(const char *name, dt_dev_operation_t op, const int32_t version, const float min, const float max)
void dt_gui_presets_update_mml(const char *name, dt_dev_operation_t op, const int32_t version, const char *maker, const char *model, const char *lens)
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled, const dt_develop_blend_colorspace_t blend_cst)
void dt_gui_throttle_cancel(gpointer source)
void dt_gui_throttle_queue(gpointer source, dt_gui_throttle_callback_t callback, gpointer user_data)
void dt_iop_throttled_history_update(gpointer data)
void dt_iop_default_init(dt_iop_module_t *module)
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)
@ DT_REQUEST_COLORPICK_MODULE
@ IOP_FLAGS_SUPPORTS_BLENDING
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
static void dt_iop_estimate_exp(const float *const x, const float *const y, const int num, float *coeff)
static float dt_iop_eval_exp(const float *const coeff, const float x)
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)
void init(dt_iop_module_t *module)
static float to_lin(const float x, const float base, const int ch, const int semilog, const int is_ordinate)
static gboolean area_resized(GtkWidget *widget, GdkEvent *event, gpointer user_data)
const char ** description(struct dt_iop_module_t *self)
struct dt_iop_tonecurve_params_t dt_iop_tonecurve_params_t
static void interpolator_callback(GtkWidget *widget, dt_iop_module_t *self)
static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
#define DT_IOP_TONECURVE_MAXNODES
static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
static gboolean dt_iop_tonecurve_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
dt_iop_tonecurve_autoscale_t
@ DT_S_SCALE_AUTOMATIC_RGB
@ DT_S_SCALE_AUTOMATIC_XYZ
#define DT_GUI_CURVE_EDITOR_INSET
static float eval_grey(float x)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
struct dt_iop_tonecurve_params_t preset
void gui_reset(struct dt_iop_module_t *self)
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
static int _add_node(dt_iop_tonecurve_node_t *tonecurve, int *nodes, float x, float y)
static gboolean dt_iop_tonecurve_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
void gui_init(struct dt_iop_module_t *self)
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
static void dt_iop_tonecurve_sanity_check(dt_iop_module_t *self, GtkWidget *widget)
static void logbase_callback(GtkWidget *slider, dt_iop_module_t *self)
void cleanup_global(dt_iop_module_so_t *module)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
#define TONECURVE_DEFAULT_STEP
void gui_cleanup(struct dt_iop_module_t *self)
void init_presets(dt_iop_module_so_t *self)
static gboolean dt_iop_tonecurve_enter_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
#define DT_IOP_TONECURVE_RES
__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 i, void *const o)
struct dt_iop_tonecurve_node_t dt_iop_tonecurve_node_t
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void picker_scale(const float *in, float *out)
static gboolean _scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
static const struct @60 preset_camera_curves[]
void init_global(dt_iop_module_so_t *module)
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void tab_switch(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data)
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 gboolean _move_point_internal(dt_iop_module_t *self, GtkWidget *widget, float dx, float dy, guint state)
static float to_log(const float x, const float base, const int ch, const int semilog, const int is_ordinate)
dt_iop_order_iccprofile_info_t * dt_ioppr_add_profile_info_to_list(struct dt_develop_t *dev, const dt_colorspaces_color_profile_type_t profile_type, const char *profile_filename, const int intent)
static dt_aligned_pixel_t float *const const float unbounded_coeffs[3][3]
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
float dt_aligned_pixel_t[4]
@ DT_DEV_PIXELPIPE_PREVIEW
struct _GtkWidget GtkWidget
const float uint32_t state[4]
struct dt_gui_gtk_t * gui
struct dt_bauhaus_t * bauhaus
struct dt_develop_t * develop
PangoFontDescription * pango_font_desc
lib_colorpicker_sample_statistics lab
dt_dev_request_flags_t request_histogram
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
struct dt_develop_t::@19 color_picker
Authoritative darkroom color-picker state.
GModule *dt_dev_operation_t op
dt_iop_global_data_t * data
dt_dev_request_colorpick_flags_t request_color_pick
dt_iop_params_t * default_params
struct dt_develop_t * dev
dt_iop_gui_data_t * gui_data
uint32_t histogram_max[4]
dt_iop_global_data_t * global_data
dt_aligned_pixel_t picked_output_color
dt_aligned_pixel_t picked_color_min
dt_aligned_pixel_t picked_color_max
dt_aligned_pixel_t picked_color
Region of interest passed through the pixelpipe.
dt_draw_curve_t * curve[3]
float unbounded_coeffs_ab[12]
float unbounded_coeffs_L[3]
float picked_color_max[3]
float picked_color_min[3]
float picked_output_color[3]
dt_draw_curve_t * minmax_curve[3]
GtkNotebook * channel_tabs
GtkWidget * preserve_colors
tonecurve_channel_t channel
int minmax_curve_nodes[3]
int tonecurve_autoscale_ab
dt_iop_tonecurve_node_t tonecurve[3][20]
dt_iop_tonecurve_node_t tonecurve[3][20]
int tonecurve_autoscale_ab
dt_iop_tonecurve_node_t tonecurve[3][20]
dt_iop_tonecurve_autoscale_t tonecurve_autoscale_ab
dt_iop_rgb_norms_t preserve_colors