87#define INVERSE_SQRT_3 0.5773502691896258f
88#define SAFETY_MARGIN 0.01f
90#define DT_GUI_CURVE_EDITOR_INSET DT_PIXEL_APPLY_DPI(1)
400 return _(
"tone mapping|curve|view transform|contrast|saturation|highlights");
406 "for display on SDR screens and paper prints\n"
407 "while preventing clipping in non-destructive ways"),
408 _(
"corrective and creative"),
409 _(
"linear or non-linear, RGB, scene-referred"),
410 _(
"non-linear, RGB"),
411 _(
"non-linear, RGB, display-referred"));
474 geometry->
grey_display = powf(CLAMP(
p->grey_point_target,
p->black_point_target,
p->white_point_target) / 100.0f,
475 1.0f /
p->output_power);
477 geometry->
grey_display = powf(0.1845f, 1.0f /
p->output_power);
479 const float dynamic_range =
p->white_point_source -
p->black_point_source;
480 geometry->
grey_log = fabsf(
p->black_point_source) / dynamic_range;
481 geometry->
black_display = powf(CLAMP(
p->black_point_target, 0.0f,
p->grey_point_target) / 100.0f,
482 1.0f /
p->output_power);
483 geometry->
white_display = powf(fmaxf(
p->white_point_target,
p->grey_point_target) / 100.0f,
484 1.0f /
p->output_power);
486 const float slope =
p->contrast * dynamic_range / 8.0f;
487 float min_contrast = 1.0f;
488 min_contrast = fmaxf(min_contrast,
490 min_contrast = fmaxf(min_contrast,
495 const float clamped_contrast = CLAMP(geometry->
contrast, min_contrast, 100.0f);
497 geometry->
contrast = clamped_contrast;
519 const float latitude = CLAMP(
p->latitude, 0.0f, 100.0f) / 100.0f;
520 const float balance = CLAMP(
p->balance, -50.0f, 50.0f) / 100.0f;
529 const float balance_correction = (balance > 0.0f)
532 nodes->
toe_log -= balance_correction;
543 float *
const toe,
float *
const shoulder)
549 *toe = CLAMP(
p->latitude, 0.0f, 100.0f);
550 *shoulder = CLAMP(
p->latitude, 0.0f, 100.0f);
554 const float toe_span = fmaxf(geometry.
grey_log - geometry.
xmin, 1e-6f);
555 const float shoulder_span = fmaxf(geometry.
xmax - geometry.
grey_log, 1e-6f);
556 *toe = CLAMP((geometry.
grey_log - nodes.
toe_log) / toe_span, 0.0f, 1.0f) * 100.0f;
557 *shoulder = CLAMP((nodes.
shoulder_log - geometry.
grey_log) / shoulder_span, 0.0f, 1.0f) * 100.0f;
561 const float toe,
const float shoulder,
562 float *
const latitude,
float *
const balance)
567 *latitude =
p->latitude;
568 *balance =
p->balance;
572 const float toe_value = CLAMP(toe, 0.0f, 100.0f) / 100.0f;
573 const float shoulder_value = CLAMP(shoulder, 0.0f, 100.0f) / 100.0f;
574 const float toe_span = fmaxf(geometry.
grey_log - geometry.
xmin, 1e-6f);
575 const float shoulder_span = fmaxf(geometry.
xmax - geometry.
grey_log, 1e-6f);
576 const float latitude_value = CLAMP((toe_span * toe_value + shoulder_span * shoulder_value)
577 / (toe_span + shoulder_span),
580 float balance_value = 0.0f;
581 if(latitude_value > 1e-6f)
583 if(toe_value > shoulder_value)
584 balance_value = 0.5f * (1.0f - shoulder_value / latitude_value);
585 else if(shoulder_value > toe_value)
586 balance_value = 0.5f * (toe_value / latitude_value - 1.0f);
589 *latitude = latitude_value * 100.0f;
590 *balance = CLAMP(balance_value, -0.5f, 0.5f) * 100.0f;
603 float grey_log = spline.
x[2];
604 float toe_log = fminf(spline.
x[1], grey_log);
605 float shoulder_log = fmaxf(spline.
x[3], grey_log);
606 float black_display = spline.
y[0];
607 float grey_display = spline.
y[2];
608 float white_display = spline.
y[4];
609 const float scaled_safety_margin =
SAFETY_MARGIN * (white_display - black_display);
610 float toe_display = fminf(spline.
y[1], grey_display);
611 float shoulder_display = fmaxf(spline.
y[3], grey_display);
613 float hardness =
n->output_power;
614 float contrast = (shoulder_display - toe_display) / (shoulder_log - toe_log);
616 float linear_intercept = grey_display - (contrast * grey_log);
617 if(toe_display < black_display + scaled_safety_margin)
619 toe_display = black_display + scaled_safety_margin;
621 toe_log = (toe_display - linear_intercept) / contrast;
623 if(shoulder_display > white_display - scaled_safety_margin)
625 shoulder_display = white_display - scaled_safety_margin;
627 shoulder_log = (shoulder_display - linear_intercept) / contrast;
630 contrast *= 8.0f / (
n->white_point_source -
n->black_point_source);
631 contrast *= hardness * powf(grey_display, hardness-1.0f);
633 const float latitude = CLAMP((shoulder_display - toe_display) / ((white_display - black_display) - 2.0f * scaled_safety_margin), 0.0f, 0.99f);
635 float toe_display_ref = latitude * (black_display + scaled_safety_margin) + (1.0f - latitude) * grey_display;
636 float shoulder_display_ref = latitude * (white_display - scaled_safety_margin) + (1.0f - latitude) * grey_display;
638 if(shoulder_display < shoulder_display_ref)
639 balance = 0.5f * (1.0f - fmaxf(shoulder_display - grey_display, 0.0f) / fmaxf(shoulder_display_ref - grey_display, 1E-5f));
641 balance = -0.5f * (1.0f - fmaxf(grey_display - toe_display, 0.0f) / fmaxf(grey_display - toe_display_ref, 1E-5f));
648 n->black_point_target = powf(black_display, hardness) * 100.0f;
649 n->white_point_target = powf(white_display, hardness) * 100.0f;
651 n->latitude = latitude * 100.0f;
652 n->contrast = contrast;
653 n->balance = balance * 100.0f;
658 const int new_version)
660 if(old_version == 1 && new_version == 5)
662 typedef struct dt_iop_filmicrgb_params_v1_t
664 float grey_point_source;
665 float black_point_source;
666 float white_point_source;
667 float security_factor;
668 float grey_point_target;
669 float black_point_target;
670 float white_point_target;
677 } dt_iop_filmicrgb_params_v1_t;
679 dt_iop_filmicrgb_params_v1_t *o = (dt_iop_filmicrgb_params_v1_t *)old_params;
685 n->grey_point_source = o->grey_point_source;
686 n->white_point_source = o->white_point_source;
687 n->black_point_source = o->black_point_source;
688 n->security_factor = o->security_factor;
689 n->grey_point_target = o->grey_point_target;
690 n->black_point_target = o->black_point_target;
691 n->white_point_target = o->white_point_target;
692 n->output_power = o->output_power;
693 n->latitude = o->latitude;
694 n->contrast = o->contrast;
695 n->saturation = o->saturation;
696 n->balance = o->balance;
697 n->preserve_color = o->preserve_color;
700 n->reconstruct_threshold
702 n->reconstruct_bloom_vs_details =
d->reconstruct_bloom_vs_details;
703 n->reconstruct_grey_vs_color =
d->reconstruct_grey_vs_color;
704 n->reconstruct_structure_vs_texture =
d->reconstruct_structure_vs_texture;
705 n->reconstruct_feather = 3.0f;
707 n->auto_hardness =
TRUE;
708 n->custom_grey =
TRUE;
709 n->high_quality_reconstruction = 0;
710 n->noise_distribution =
d->noise_distribution;
711 n->noise_level = 0.f;
713 n->compensate_icc_black =
FALSE;
717 if(old_version == 2 && new_version == 5)
719 typedef struct dt_iop_filmicrgb_params_v2_t
721 float grey_point_source;
722 float black_point_source;
723 float white_point_source;
724 float reconstruct_threshold;
725 float reconstruct_feather;
726 float reconstruct_bloom_vs_details;
727 float reconstruct_grey_vs_color;
728 float reconstruct_structure_vs_texture;
729 float security_factor;
730 float grey_point_target;
731 float black_point_target;
732 float white_point_target;
742 int high_quality_reconstruction;
745 } dt_iop_filmicrgb_params_v2_t;
747 dt_iop_filmicrgb_params_v2_t *o = (dt_iop_filmicrgb_params_v2_t *)old_params;
753 n->grey_point_source = o->grey_point_source;
754 n->white_point_source = o->white_point_source;
755 n->black_point_source = o->black_point_source;
756 n->security_factor = o->security_factor;
757 n->grey_point_target = o->grey_point_target;
758 n->black_point_target = o->black_point_target;
759 n->white_point_target = o->white_point_target;
760 n->output_power = o->output_power;
761 n->latitude = o->latitude;
762 n->contrast = o->contrast;
763 n->saturation = o->saturation;
764 n->balance = o->balance;
765 n->preserve_color = o->preserve_color;
766 n->shadows = o->shadows;
767 n->highlights = o->highlights;
768 n->reconstruct_threshold = o->reconstruct_threshold;
769 n->reconstruct_bloom_vs_details = o->reconstruct_bloom_vs_details;
770 n->reconstruct_grey_vs_color = o->reconstruct_grey_vs_color;
771 n->reconstruct_structure_vs_texture = o->reconstruct_structure_vs_texture;
772 n->reconstruct_feather = o->reconstruct_feather;
773 n->version = o->version;
774 n->auto_hardness = o->auto_hardness;
775 n->custom_grey = o->custom_grey;
776 n->high_quality_reconstruction = o->high_quality_reconstruction;
777 n->noise_level =
d->noise_level;
778 n->noise_distribution =
d->noise_distribution;
779 n->noise_level = 0.f;
781 n->compensate_icc_black =
FALSE;
785 if(old_version == 3 && new_version == 5)
787 typedef struct dt_iop_filmicrgb_params_v3_t
789 float grey_point_source;
790 float black_point_source;
791 float white_point_source;
792 float reconstruct_threshold;
793 float reconstruct_feather;
794 float reconstruct_bloom_vs_details;
796 float reconstruct_grey_vs_color;
798 float reconstruct_structure_vs_texture;
800 float security_factor;
801 float grey_point_target;
802 float black_point_target;
803 float white_point_target;
814 gboolean auto_hardness;
815 gboolean custom_grey;
816 int high_quality_reconstruction;
818 int noise_distribution;
822 } dt_iop_filmicrgb_params_v3_t;
824 dt_iop_filmicrgb_params_v3_t *o = (dt_iop_filmicrgb_params_v3_t *)old_params;
830 n->grey_point_source = o->grey_point_source;
831 n->white_point_source = o->white_point_source;
832 n->black_point_source = o->black_point_source;
833 n->security_factor = o->security_factor;
834 n->grey_point_target = o->grey_point_target;
835 n->black_point_target = o->black_point_target;
836 n->white_point_target = o->white_point_target;
837 n->output_power = o->output_power;
838 n->latitude = o->latitude;
839 n->contrast = o->contrast;
840 n->saturation = o->saturation;
841 n->balance = o->balance;
842 n->preserve_color = o->preserve_color;
843 n->shadows = o->shadows;
844 n->highlights = o->highlights;
845 n->reconstruct_threshold = o->reconstruct_threshold;
846 n->reconstruct_bloom_vs_details = o->reconstruct_bloom_vs_details;
847 n->reconstruct_grey_vs_color = o->reconstruct_grey_vs_color;
848 n->reconstruct_structure_vs_texture = o->reconstruct_structure_vs_texture;
849 n->reconstruct_feather = o->reconstruct_feather;
850 n->version = o->version;
851 n->auto_hardness = o->auto_hardness;
852 n->custom_grey = o->custom_grey;
853 n->high_quality_reconstruction = o->high_quality_reconstruction;
854 n->noise_level =
d->noise_level;
855 n->noise_distribution =
d->noise_distribution;
856 n->noise_level =
d->noise_level;
858 n->compensate_icc_black =
FALSE;
862 if(old_version == 4 && new_version == 5)
864 typedef struct dt_iop_filmicrgb_params_v4_t
866 float grey_point_source;
867 float black_point_source;
868 float white_point_source;
869 float reconstruct_threshold;
870 float reconstruct_feather;
871 float reconstruct_bloom_vs_details;
872 float reconstruct_grey_vs_color;
873 float reconstruct_structure_vs_texture;
874 float security_factor;
875 float grey_point_target;
876 float black_point_target;
877 float white_point_target;
886 gboolean auto_hardness;
887 gboolean custom_grey;
888 int high_quality_reconstruction;
892 gboolean compensate_icc_black;
893 gint internal_version;
894 } dt_iop_filmicrgb_params_v4_t;
896 dt_iop_filmicrgb_params_v4_t *o = (dt_iop_filmicrgb_params_v4_t *)old_params;
900 switch(o->internal_version)
920static inline __attribute__((always_inline))
float pixel_rgb_norm_power_simd(
const dt_aligned_pixel_simd_t pixel)
925 float numerator = 0.0f;
926 float denominator = 0.0f;
928 for(
int c = 0; c < 3; c++)
930 const float value = fabsf(pixel[c]);
932 const float RGB_cubic = RGB_square *
value;
933 numerator += RGB_cubic;
934 denominator += RGB_square;
937 return numerator / fmaxf(denominator, 1e-12f);
943 return pixel_rgb_norm_power_simd(dt_load_simd_aligned(pixel));
960 return fmaxf(fmaxf(pixel[0], pixel[1]), pixel[2]);
969 return dt_ioppr_get_rgb_matrix_luminance(
rgb, work_profile->
matrix_in, work_profile->
lut_in,
970 work_profile->unbounded_coeffs_in, work_profile->
lutsize,
974 return work_profile->
matrix_in[1][0] * pixel[0] + work_profile->
matrix_in[1][1] * pixel[1]
975 + work_profile->
matrix_in[1][2] * pixel[2];
978 return pixel[0] * 0.2225045f + pixel[1] * 0.7168786f + pixel[2] * 0.0606169f;
981 return pixel_rgb_norm_power_simd(pixel);
984 return sqrtf(sqf(pixel[0]) + sqf(pixel[1]) + sqf(pixel[2]));
987 return sqrtf(sqf(pixel[0]) + sqf(pixel[1]) + sqf(pixel[2])) *
INVERSE_SQRT_3;
996 return dt_ioppr_get_rgb_matrix_luminance(
rgb, work_profile->
matrix_in, work_profile->
lut_in,
997 work_profile->unbounded_coeffs_in, work_profile->
lutsize,
1001 return work_profile->
matrix_in[1][0] * pixel[0] + work_profile->
matrix_in[1][1] * pixel[1]
1002 + work_profile->
matrix_in[1][2] * pixel[2];
1005 return pixel[0] * 0.2225045f + pixel[1] * 0.7168786f + pixel[2] * 0.0606169f;
1014 return get_pixel_norm_simd(dt_load_simd_aligned(pixel), variant, work_profile);
1019 const
float dynamic_range)
1021 return clamp_simd((log2f(
x / grey) - black) / dynamic_range);
1026 const
float dynamic_range)
1029 return grey * exp2f(dynamic_range *
x + black);
1048 if(
x < latitude_min)
1060 result = M3[2] + fmaxf(0.f, M3[0] * powf(fmaxf(
x, 0.f), M4[0]));
1065 const float ty = latitude_min * M2[2] + M1[2];
1066 const float u = M2[2] * (
x - latitude_min) / M1[0];
1067 result = M1[0] * (u / powf(1.f + powf(u, M2[0]), 1.f / M2[0])) + ty;
1073 result = M1[0] +
x * (M2[0] +
x * (M3[0] +
x * (M4[0] +
x * M5[0])));
1078 result = M1[0] +
x * (M2[0] +
x * (M3[0] +
x * M4[0]));
1083 const float xi = latitude_min -
x;
1084 const float rat = xi * (xi * M2[0] + 1.f);
1085 result = M4[0] - M1[0] * rat / (rat + M3[0]);
1088 else if(
x > latitude_max)
1096 result = M4[2] - fmaxf(0.f, M3[1] * powf(fmaxf(1.f -
x, 0.f), M4[1]));
1101 const float ty = latitude_max * M2[2] + M1[2];
1102 const float u = M2[2] * (
x - latitude_max) / M1[1];
1103 result = M1[1] * (u / powf(1.f + powf(u, M2[1]), 1.f / M2[1])) + ty;
1109 result = M1[1] +
x * (M2[1] +
x * (M3[1] +
x * (M4[1] +
x * M5[1])));
1114 result = M1[1] +
x * (M2[1] +
x * (M3[1] +
x * M4[1]));
1119 const float xi =
x - latitude_max;
1120 const float rat = xi * (xi * M2[1] + 1.f);
1121 result = M4[1] + M1[1] * rat / (rat + M3[1]);
1127 result = M1[2] +
x * M2[2];
1135filmic_desaturate_v1(
const float x,
const float sigma_toe,
const float sigma_shoulder,
1136 const float saturation)
1138 const float radius_toe =
x;
1139 const float radius_shoulder = 1.0f -
x;
1141 const float key_toe = expf(-0.5f * radius_toe * radius_toe / sigma_toe);
1142 const float key_shoulder = expf(-0.5f * radius_shoulder * radius_shoulder / sigma_shoulder);
1144 return 1.0f -
clamp_simd((key_toe + key_shoulder) / saturation);
1150filmic_desaturate_v2(
const float x,
const float sigma_toe,
const float sigma_shoulder,
1151 const float saturation)
1153 const float radius_toe =
x;
1154 const float radius_shoulder = 1.0f -
x;
1155 const float sat2 = 0.5f / sqrtf(saturation);
1156 const float key_toe = expf(-radius_toe * radius_toe / sigma_toe * sat2);
1157 const float key_shoulder = expf(-radius_shoulder * radius_shoulder / sigma_shoulder * sat2);
1159 return (saturation - (key_toe + key_shoulder) * (saturation));
1170#define MAX_NUM_SCALES 10
1173 const float normalize,
const float feathering,
const size_t width,
1174 const size_t height,
const size_t ch)
1186 const float pix_max = fmaxf(sqrtf(sqf(in[
k]) + sqf(in[
k + 1]) + sqf(in[
k + 2])), 0.f);
1187 const float argument = -pix_max *
normalize + feathering;
1195 clipped += (4.f > argument);
1199 return (clipped > 9);
1202 float *
const inpainted,
const float noise_level,
const float threshold,
1211 for(
size_t j = 0; j <
width; j++)
1221 const size_t idx =
i *
width + j;
1222 const size_t index = idx * 4;
1223 const float weight = mask[idx];
1224 const float *
const restrict pix_in = __builtin_assume_aligned(in + index, 16);
1236 float *
const restrict pix_out = __builtin_assume_aligned(inpainted + index, 16);
1244 const float *
const restrict texture,
const float *
const restrict mask,
1245 float *
const restrict reconstructed,
const size_t width,
1246 const size_t height,
const size_t ch,
const float gamma,
1247 const float gamma_comp,
const float beta,
const float beta_comp,
1248 const float delta,
const size_t s,
const size_t scales)
1253 const float alpha = mask[
k /
ch];
1256 const float *
const restrict HF_c = __builtin_assume_aligned(HF +
k, 16);
1257 const float *
const restrict LF_c = __builtin_assume_aligned(LF +
k, 16);
1258 const float *
const restrict TT_c = __builtin_assume_aligned(texture +
k, 16);
1267 const float grey_details = (HF_c[0] + HF_c[1] + HF_c[2]) / 3.f;
1272 const float grey_HF = beta_comp * (gamma_comp * grey_details + gamma * grey_texture);
1276 const float grey_residual = beta_comp * (LF_c[0] + LF_c[1] + LF_c[2]) / 3.f;
1277 __OMP_SIMD__(aligned(reconstructed:64) aligned(HF_c, LF_c, TT_c:16))
1278 for(
size_t c = 0; c < 4; c++)
1285 const float details = (gamma_comp * HF_c[c] + gamma * TT_c[c]) * beta + grey_HF;
1288 const float residual = (s == scales - 1) ? (grey_residual + LF_c[c] * beta) : 0.f;
1289 reconstructed[
k + c] += alpha * (
delta * details + residual);
1296 const float *
const restrict texture,
1297 const float *
const restrict mask,
1298 float *
const restrict reconstructed,
const size_t width,
1299 const size_t height,
const size_t ch,
const float gamma,
1300 const float gamma_comp,
const float beta,
const float beta_comp,
1301 const float delta,
const size_t s,
const size_t scales)
1319 const float alpha = mask[
k /
ch];
1322 const float *
const restrict HF_c = __builtin_assume_aligned(HF +
k, 16);
1323 const float *
const restrict LF_c = __builtin_assume_aligned(LF +
k, 16);
1324 const float *
const restrict TT_c = __builtin_assume_aligned(texture +
k, 16);
1333 const float grey_details = (HF_c[0] + HF_c[1] + HF_c[2]) / 3.f;
1338 const float grey_HF = (gamma_comp * grey_details + gamma * grey_texture);
1340 for(
size_t c = 0; c < 4; c++)
1344 const float details = 0.5f * ((gamma_comp * HF_c[c] + gamma * TT_c[c]) + grey_HF);
1347 const float residual = (s == scales - 1) ? LF_c[c] : 0.f;
1348 reconstructed[
k + c] += alpha * (
delta * details + residual);
1355static inline void init_reconstruct(
const float *
const restrict in,
const float *
const restrict mask,
1356 float *
const restrict reconstructed,
const size_t width,
1365 reconstructed[4*
k + c] = fmaxf(in[4*
k + c] * (1.f - mask[
k]), 0.f);
1372 float *
const restrict HF,
float *
const restrict texture,
1377 for(
size_t c = 0; c < 4; ++c) HF[4*
k + c] = texture[4*
k + c] = detail[4*
k + c] - LF[4*
k + c];
1402 const float *
const restrict in,
const float *
const restrict mask,
1403 float *
const restrict reconstructed,
1411 const int scales =
get_scales(pipe, roi_in, piece);
1447 for(
int s = 0; s < scales; ++s)
1449 const float *restrict detail;
1451 float *restrict HF_RGB_temp;
1458 HF_RGB_temp = LF_even;
1464 HF_RGB_temp = LF_odd;
1470 HF_RGB_temp = LF_even;
1473 const int mult = 1 << s;
1488 gamma, gamma_comp, beta, beta_comp,
delta, s, scales);
1491 gamma, gamma_comp, beta, beta_comp,
delta, s, scales);
1514 const float *
const restrict pix_in = in +
k;
1515 float *
const restrict pix_out =
out +
k;
1519 for(
int c = 0; c < 3; c++)
1524 const float lum = (work_profile)
1525 ? dt_ioppr_get_rgb_matrix_luminance(temp, work_profile->
matrix_in, work_profile->
lut_in,
1526 work_profile->unbounded_coeffs_in,
1534 for(
int c = 0; c < 3; c++)
1537 spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
1539 spline.
y[0], spline.
y[4]),
1555 const float *
const restrict pix_in = in +
k;
1556 float *
const restrict pix_out =
out +
k;
1560 for(
int c = 0; c < 3; c++)
1565 const float lum = (work_profile)
1566 ? dt_ioppr_get_rgb_matrix_luminance(temp, work_profile->
matrix_in, work_profile->
lut_in,
1567 work_profile->unbounded_coeffs_in,
1575 for(
int c = 0; c < 3; c++)
1578 spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
1580 spline.
y[0], spline.
y[4]),
1596 const float *
const restrict pix_in = in +
k;
1597 float *
const restrict pix_out =
out +
k;
1600 float norm = fmaxf(get_pixel_norm(pix_in, variant, work_profile),
NORM_MIN);
1604 ratios[c] = pix_in[c] / norm;
1607 const float min_ratios = fminf(fminf(ratios[0], ratios[1]), ratios[2]);
1608 if(min_ratios < 0.0f)
1619 const float lum = (work_profile) ? dt_ioppr_get_rgb_matrix_luminance(
1620 ratios, work_profile->
matrix_in, work_profile->
lut_in, work_profile->unbounded_coeffs_in,
1625 for(
int c = 0; c < 3; c++) ratios[c] =
linear_saturation(ratios[c], lum, desaturation) / norm;
1629 norm = powf(
CLAMPF(filmic_spline(norm, spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
1631 spline.
y[0], spline.
y[4]),
1651 const float *
const restrict pix_in = in +
k;
1652 float *
const restrict pix_out =
out +
k;
1654 float norm = fmaxf(get_pixel_norm(pix_in, variant, work_profile),
NORM_MIN);
1660 ratios[c] = pix_in[c] / norm;
1663 const float min_ratios = fminf(fminf(ratios[0], ratios[1]), ratios[2]);
1664 const int sanitize = (min_ratios < 0.0f);
1668 ratios[c] -= min_ratios;
1678 norm = powf(
CLAMPF(filmic_spline(norm, spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
1680 spline.
y[0], spline.
y[4]),
1684 for(
int c = 0; c < 3; c++) ratios[c] = fmaxf(ratios[c] + (1.0f - ratios[c]) * (1.0f - desaturation), 0.0f);
1689 norm /= fmaxf(get_pixel_norm(ratios, variant, work_profile),
NORM_MIN);
1692 pix_out[c] = ratios[c] * norm;
1695 const float max_pix = fmaxf(fmaxf(pix_out[0], pix_out[1]), pix_out[2]);
1696 const int penalize = (max_pix > 1.0f);
1703 ratios[c] = fmaxf(ratios[c] + (1.0f - max_pix), 0.0f);
1704 pix_out[c] = ratios[c] * norm;
1711static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1712pipe_RGB_to_Ych_simd(
const dt_aligned_pixel_simd_t in,
const dt_aligned_pixel_simd_t matrix0,
1713 const dt_aligned_pixel_simd_t matrix1,
const dt_aligned_pixel_simd_t matrix2)
1724 const dt_aligned_pixel_simd_t
Yrg = LMS_to_Yrg_simd(dt_mat3x4_mul_vec4(in, matrix0, matrix1, matrix2));
1725 const float r =
Yrg[1] - 0.21902143f;
1726 const float g =
Yrg[2] - 0.54371398f;
1727 const float c = dt_fast_hypotf(
g,
r);
1728 const float cos_h =
c != 0.f ?
r /
c : 1.f;
1729 const float sin_h =
c != 0.f ?
g /
c : 0.f;
1730 return (dt_aligned_pixel_simd_t){
Yrg[0],
c, cos_h, sin_h };
1734static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1735Ych_to_pipe_RGB_simd(
const dt_aligned_pixel_simd_t in,
const dt_aligned_pixel_simd_t matrix0,
1736 const dt_aligned_pixel_simd_t matrix1,
const dt_aligned_pixel_simd_t matrix2)
1741 const dt_aligned_pixel_simd_t
Yrg = {
1743 in[1] * in[2] + 0.21902143f,
1744 in[1] * in[3] + 0.54371398f,
1747 return dt_mat3x4_mul_vec4(Yrg_to_LMS_simd(Yrg), matrix0, matrix1, matrix2);
1750static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1751filmic_desaturate_v4(
const dt_aligned_pixel_simd_t Ych_original, dt_aligned_pixel_simd_t Ych_final,
1752 const float saturation)
1760 const float chroma_original = Ych_original[1] * Ych_original[0];
1761 float chroma_final = Ych_final[1] * Ych_final[0];
1770 const float delta_chroma = saturation * (chroma_original - chroma_final);
1772 const int filmic_brightens = (Ych_final[0] > Ych_original[0]);
1773 const int filmic_resat = (chroma_original < chroma_final);
1774 const int filmic_desat = (chroma_original > chroma_final);
1775 const int user_resat = (saturation > 0.f);
1776 const int user_desat = (saturation < 0.f);
1778 chroma_final = (filmic_brightens && filmic_resat)
1779 ? (chroma_original + chroma_final) / 2.f
1780 : ((user_resat && filmic_desat) || user_desat)
1781 ? chroma_final + delta_chroma
1784 Ych_final[1] = fmaxf(chroma_final / Ych_final[0], 0.f);
1794#define CIE_Y_1931_to_CIE_Y_2006(x) (1.05785528f * (x))
1798clip_chroma_white_raw(
const float coeffs[3],
const float target_white,
const float Y,
1799 const float cos_h,
const float sin_h)
1801 const float denominator_Y_coeff = coeffs[0] * (0.979381443298969f * cos_h + 0.391752577319588f * sin_h)
1802 + coeffs[1] * (0.0206185567010309f * cos_h + 0.608247422680412f * sin_h)
1803 - coeffs[2] * (cos_h + sin_h);
1804 const float denominator_target_term = target_white * (0.68285981628866f * cos_h + 0.482137060515464f * sin_h);
1807 if(denominator_Y_coeff == 0.f)
return FLT_MAX;
1812 const float Y_asymptote = denominator_target_term / denominator_Y_coeff;
1813 if(Y <= Y_asymptote)
return FLT_MAX;
1819 const float denominator = Y * denominator_Y_coeff - denominator_target_term;
1820 const float numerator = -0.427506877216495f
1821 * (Y * (coeffs[0] + 0.856492345150334f * coeffs[1] + 0.554995960637719f * coeffs[2])
1822 - 0.988237752433297f * target_white);
1824 return numerator / denominator;
1829clip_chroma_white(
const float coeffs[3],
const float target_white,
const float Y,
1830 const float cos_h,
const float sin_h)
1836 const float eps = 1e-3f;
1838 const float delta_Y =
MAX(max_Y - Y, 0.f);
1842 max_chroma = delta_Y / (
eps * max_Y) * clip_chroma_white_raw(coeffs, target_white, (1.f -
eps) * max_Y, cos_h, sin_h);
1846 max_chroma = clip_chroma_white_raw(coeffs, target_white, Y, cos_h, sin_h);
1848 return max_chroma >= 0.f ? max_chroma : FLT_MAX;
1853clip_chroma_black(
const float coeffs[3],
const float cos_h,
const float sin_h)
1862 const float denominator = coeffs[0] * (0.979381443298969f * cos_h + 0.391752577319588f * sin_h)
1863 + coeffs[1] * (0.0206185567010309f * cos_h + 0.608247422680412f * sin_h)
1864 - coeffs[2] * (cos_h + sin_h);
1867 if(denominator == 0.f)
return FLT_MAX;
1869 const float numerator = -0.427506877216495f * (coeffs[0] + 0.856492345150334f * coeffs[1] + 0.554995960637719f * coeffs[2]);
1870 const float max_chroma = numerator / denominator;
1871 return max_chroma >= 0.f ? max_chroma : FLT_MAX;
1876clip_chroma(
const dt_colormatrix_t matrix_out,
const float target_white,
const float Y,
1877 const float cos_h,
const float sin_h,
const float chroma)
1885 const float chroma_R_white = clip_chroma_white(matrix_out[0], target_white, Y, cos_h, sin_h);
1886 const float chroma_G_white = clip_chroma_white(matrix_out[1], target_white, Y, cos_h, sin_h);
1887 const float chroma_B_white = clip_chroma_white(matrix_out[2], target_white, Y, cos_h, sin_h);
1888 const float max_chroma_white =
MIN(
MIN(chroma_R_white, chroma_G_white), chroma_B_white);
1890 const float chroma_R_black = clip_chroma_black(matrix_out[0], cos_h, sin_h);
1891 const float chroma_G_black = clip_chroma_black(matrix_out[1], cos_h, sin_h);
1892 const float chroma_B_black = clip_chroma_black(matrix_out[2], cos_h, sin_h);
1893 const float max_chroma_black =
MIN(
MIN(chroma_R_black, chroma_G_black), chroma_B_black);
1895 return MIN(
MIN(chroma, max_chroma_black), max_chroma_white);
1899static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1900gamut_check_Yrg_filmic_simd(
const dt_aligned_pixel_simd_t Ych)
1904 const dt_aligned_pixel_simd_t
Yrg = {
1906 Ych[1] * Ych[2] + 0.21902143f,
1907 Ych[1] * Ych[3] + 0.54371398f,
1910 float max_c = Ych[1];
1912 if(Yrg[1] < 0.f) max_c = fminf(-0.21902143f / Ych[2], max_c);
1913 if(Yrg[2] < 0.f) max_c = fminf(-0.54371398f / Ych[3], max_c);
1914 if(Yrg[1] + Yrg[2] > 1.f) max_c = fminf((1.f - 0.21902143f - 0.54371398f) / (Ych[2] + Ych[3]), max_c);
1916 return (dt_aligned_pixel_simd_t){ Ych[0], max_c, Ych[2], Ych[3] };
1920static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1921gamut_check_RGB_simd(
const dt_colormatrix_t matrix_out,
const dt_aligned_pixel_simd_t matrix_in0,
1922 const dt_aligned_pixel_simd_t matrix_in1,
const dt_aligned_pixel_simd_t matrix_in2,
1923 const dt_aligned_pixel_simd_t matrix_out0,
const dt_aligned_pixel_simd_t matrix_out1,
1924 const dt_aligned_pixel_simd_t matrix_out2,
const float display_black,
1925 const float display_white,
const dt_aligned_pixel_simd_t Ych_in)
1929 dt_aligned_pixel_simd_t RGB_brightened = Ych_to_pipe_RGB_simd(Ych_in, matrix_out0, matrix_out1, matrix_out2);
1930 const float min_pix =
MIN(
MIN(RGB_brightened[0], RGB_brightened[1]), RGB_brightened[2]);
1931 const float black_offset =
MAX(-min_pix, 0.f);
1934 const dt_aligned_pixel_simd_t Ych_brightened
1935 = pipe_RGB_to_Ych_simd(RGB_brightened, matrix_in0, matrix_in1, matrix_in2);
1941 const float Y = CLAMP((Ych_in[0] + Ych_brightened[0]) / 2.f,
1944 const float new_chroma = clip_chroma(matrix_out, display_white, Y, Ych_in[2], Ych_in[3], Ych_in[1]);
1947 dt_aligned_pixel_simd_t RGB_out
1948 = Ych_to_pipe_RGB_simd((dt_aligned_pixel_simd_t){
Y, new_chroma, Ych_in[2], Ych_in[3] },
1949 matrix_out0, matrix_out1, matrix_out2);
1957static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
1958gamut_mapping_simd(dt_aligned_pixel_simd_t Ych_final,
const dt_aligned_pixel_simd_t Ych_original,
1959 const dt_colormatrix_t output_matrix,
const dt_aligned_pixel_simd_t input_matrix0,
1960 const dt_aligned_pixel_simd_t input_matrix1,
const dt_aligned_pixel_simd_t input_matrix2,
1961 const dt_aligned_pixel_simd_t output_matrix0,
const dt_aligned_pixel_simd_t output_matrix1,
1962 const dt_aligned_pixel_simd_t output_matrix2,
1963 const dt_colormatrix_t export_output_matrix,
const dt_aligned_pixel_simd_t export_input_matrix0,
1964 const dt_aligned_pixel_simd_t export_input_matrix1,
const dt_aligned_pixel_simd_t export_input_matrix2,
1965 const dt_aligned_pixel_simd_t export_output_matrix0,
const dt_aligned_pixel_simd_t export_output_matrix1,
1966 const dt_aligned_pixel_simd_t export_output_matrix2,
const float display_black,
1967 const float display_white,
const float saturation,
const int use_output_profile)
1970 Ych_final[2] = Ych_original[2];
1971 Ych_final[3] = Ych_original[3];
1977 Ych_final = filmic_desaturate_v4(Ych_original, Ych_final, saturation);
1978 Ych_final = gamut_check_Yrg_filmic_simd(Ych_final);
1980 if(!use_output_profile)
1984 return gamut_check_RGB_simd(output_matrix, input_matrix0, input_matrix1, input_matrix2,
1985 output_matrix0, output_matrix1, output_matrix2,
1986 display_black, display_white, Ych_final);
1991 dt_aligned_pixel_simd_t pix_out
1992 = gamut_check_RGB_simd(export_output_matrix, export_input_matrix0, export_input_matrix1, export_input_matrix2,
1993 export_output_matrix0, export_output_matrix1, export_output_matrix2,
1994 display_black, display_white, Ych_final);
1997 const dt_aligned_pixel_simd_t
LMS
1998 = dt_mat3x4_mul_vec4(pix_out, export_input_matrix0, export_input_matrix1, export_input_matrix2);
2000 return dt_mat3x4_mul_vec4(
LMS, output_matrix0, output_matrix1, output_matrix2);
2021 const int use_output_profile = (!
IS_NULL_PTR(export_profile));
2022 if(use_output_profile)
2033 return use_output_profile;
2070 simd_matrices->
input[
row] = dt_colormatrix_row_to_simd(input_matrix_t,
row);
2071 simd_matrices->
output[
row] = dt_colormatrix_row_to_simd(output_matrix_t,
row);
2072 simd_matrices->
export_input[
row] = dt_colormatrix_row_to_simd(export_input_matrix_t,
row);
2073 simd_matrices->
export_output[
row] = dt_colormatrix_row_to_simd(export_output_matrix_t,
row);
2077static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
2078norm_tone_mapping_v4_simd(
const dt_aligned_pixel_simd_t pix_in,
2083 const float norm_min,
const float norm_max)
2087 float norm =
CLAMPF(get_pixel_norm_simd(pix_in,
type, work_profile), norm_min, norm_max);
2089 const dt_aligned_pixel_simd_t ratios = pix_in /
dt_simd_set1(norm);
2095 norm = powf(
CLAMPF(filmic_spline(norm, spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
2097 spline.
y[0], spline.
y[4]),
2104static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
2110 dt_aligned_pixel_simd_t pix_out = pix_in;
2111 for(
size_t c = 0;
c < 3;
c++)
2114 pix_out[
c] = powf(
CLAMPF(filmic_spline(mapped, spline.
M1, spline.
M2, spline.
M3, spline.
M4, spline.
M5,
2131 const float display_black,
const float display_white)
2139 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
2140 export_output_matrix, work_profile, export_profile);
2149 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2150 const dt_aligned_pixel_simd_t pix_out
2151 = norm_tone_mapping_v4_simd(pix_in, variant, work_profile, data, spline, norm_min, norm_max);
2154 const dt_aligned_pixel_simd_t Ych_original = pipe_RGB_to_Ych_simd(pix_in, simd_matrices.
input[0],
2155 simd_matrices.
input[1], simd_matrices.
input[2]);
2156 const dt_aligned_pixel_simd_t Ych_final = pipe_RGB_to_Ych_simd(pix_out, simd_matrices.
input[0],
2157 simd_matrices.
input[1], simd_matrices.
input[2]);
2159 dt_store_simd_nontemporal(
out +
k,
2160 gamut_mapping_simd(Ych_final, Ych_original, output_matrix,
2161 simd_matrices.
input[0], simd_matrices.
input[1], simd_matrices.
input[2],
2163 export_output_matrix,
2166 display_black, display_white, data->
saturation, use_output_profile));
2179 const float display_black,
const float display_white)
2188 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
2189 export_output_matrix, work_profile, export_profile);
2195 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2196 const dt_aligned_pixel_simd_t pix_out = RGB_tone_mapping_v4_simd(pix_in, data, spline);
2197 const dt_aligned_pixel_simd_t Ych_original = pipe_RGB_to_Ych_simd(pix_in, simd_matrices.
input[0],
2198 simd_matrices.
input[1], simd_matrices.
input[2]);
2199 dt_aligned_pixel_simd_t Ych_final = pipe_RGB_to_Ych_simd(pix_out, simd_matrices.
input[0],
2200 simd_matrices.
input[1], simd_matrices.
input[2]);
2202 Ych_final[1] = fminf(Ych_original[1], Ych_final[1]);
2204 dt_store_simd_nontemporal(
out +
k,
2205 gamut_mapping_simd(Ych_final, Ych_original, output_matrix,
2206 simd_matrices.
input[0], simd_matrices.
input[1], simd_matrices.
input[2],
2208 export_output_matrix,
2211 display_black, display_white, data->
saturation, use_output_profile));
2218static inline void filmic_v5(
const float *
const restrict in,
float *
const restrict
out,
2223 const size_t height,
const size_t ch,
const float display_black,
2224 const float display_white)
2233 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
2234 export_output_matrix, work_profile, export_profile);
2243 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2244 const dt_aligned_pixel_simd_t naive_rgb = RGB_tone_mapping_v4_simd(pix_in, data, spline);
2245 const dt_aligned_pixel_simd_t max_rgb
2252 const dt_aligned_pixel_simd_t Ych_original = pipe_RGB_to_Ych_simd(pix_in, simd_matrices.
input[0],
2253 simd_matrices.
input[1], simd_matrices.
input[2]);
2255 dt_aligned_pixel_simd_t Ych_final = pipe_RGB_to_Ych_simd(pix_out, simd_matrices.
input[0],
2256 simd_matrices.
input[1], simd_matrices.
input[2]);
2258 Ych_final[1] = fminf(Ych_original[1], Ych_final[1]);
2260 dt_store_simd_nontemporal(
out +
k,
2261 gamut_mapping_simd(Ych_final, Ych_original, output_matrix,
2262 simd_matrices.
input[0], simd_matrices.
input[1], simd_matrices.
input[2],
2264 export_output_matrix,
2267 display_black, display_white, 0.f, use_output_profile));
2289 dot_product(xyz_D50, XYZ_D50_to_D65_CAT16, xyz_D65);
2305 for(
size_t r = 0;
r < 4;
r++)
2306 for(
size_t c = 0; c < 4; c++)
M[
r][c] = (
r == c &&
r < 3) ? 1.f : 0.f;
2316 const float inset[3],
const float rotation[3],
2322 for(
size_t r = 0;
r < 3;
r++)
2323 for(
size_t c = 0; c < 3; c++) white_xyz[
r] += work_profile->
matrix_in[
r][c];
2327 for(
size_t i = 0;
i < 3;
i++)
2335 const float dr = primary_Yrg[1] - white_Yrg[1];
2336 const float dg = primary_Yrg[2] - white_Yrg[2];
2337 const float scale = 1.f -
CLAMPF(inset[
i], 0.f, 0.9f);
2338 const float cos_a = cosf(rotation[
i]);
2339 const float sin_a = sinf(rotation[
i]);
2341 white_Yrg[1] + scale * (cos_a * dr - sin_a * dg),
2342 white_Yrg[2] + scale * (sin_a * dr + cos_a * dg), 0.f };
2345 for(
size_t r = 0;
r < 3;
r++) P_prime[
r][
i] = displaced_xyz[
r];
2353 dot_product(white_xyz, P_prime_inv, s);
2354 for(
size_t r = 0;
r < 3;
r++)
2355 for(
size_t c = 0; c < 3; c++) P_prime[
r][c] *= s[c];
2380 float inset_anchor[3], rotation_anchor[3], outset_anchor[3], outset_rotation[3];
2385 inset_anchor[0] = +0.6410825f; inset_anchor[1] = +0.6898110f; inset_anchor[2] = +0.3194529f;
2386 rotation_anchor[0] = +0.0405734f; rotation_anchor[1] = +0.1631286f; rotation_anchor[2] = +0.0350584f;
2387 outset_anchor[0] = 0.784757f; outset_anchor[1] = 0.789387f; outset_anchor[2] = 0.445403f;
2388 outset_rotation[0] = -0.0057845f; outset_rotation[1] = +0.1593207f; outset_rotation[2] = -0.0592955f;
2392 inset_anchor[0] = +0.6509540f; inset_anchor[1] = +0.7488775f; inset_anchor[2] = +0.3517703f;
2393 rotation_anchor[0] = +0.0278602f; rotation_anchor[1] = +0.1214671f; rotation_anchor[2] = -0.0228829f;
2394 outset_anchor[0] = 0.793082f; outset_anchor[1] = 0.815169f; outset_anchor[2] = 0.460318f;
2395 outset_rotation[0] = -0.0053781f; outset_rotation[1] = +0.1187604f; outset_rotation[2] = -0.0794801f;
2399 inset_anchor[0] = +0.6379749f; inset_anchor[1] = +0.7878689f; inset_anchor[2] = +0.3753822f;
2400 rotation_anchor[0] = +0.0106096f; rotation_anchor[1] = +0.0582598f; rotation_anchor[2] = -0.0696729f;
2401 outset_anchor[0] = 0.790237f; outset_anchor[1] = 0.831376f; outset_anchor[2] = 0.465406f;
2402 outset_rotation[0] = -0.0080070f; outset_rotation[1] = +0.0571100f; outset_rotation[2] = -0.0912220f;
2406 inset_anchor[0] = +0.5770235f; inset_anchor[1] = +0.8102094f; inset_anchor[2] = +0.4000390f;
2407 rotation_anchor[0] = -0.0081060f; rotation_anchor[1] = -0.0034008f; rotation_anchor[2] = -0.1035236f;
2408 outset_anchor[0] = 0.766420f; outset_anchor[1] = 0.838020f; outset_anchor[2] = 0.465130f;
2409 outset_rotation[0] = -0.0122011f; outset_rotation[1] = -0.0021732f; outset_rotation[2] = -0.0971215f;
2414 inset_anchor[0] = +0.5991055f; inset_anchor[1] = +0.6000000f; inset_anchor[2] = +0.3300009f;
2415 rotation_anchor[0] = +0.0571015f; rotation_anchor[1] = +0.1999891f; rotation_anchor[2] = +0.0886110f;
2416 outset_anchor[0] = 0.761433f; outset_anchor[1] = 0.752267f; outset_anchor[2] = 0.465293f;
2417 outset_rotation[0] = -0.0034297f; outset_rotation[1] = +0.1952448f; outset_rotation[2] = -0.0480109f;
2432static inline __attribute__((always_inline)) dt_aligned_pixel_simd_t
2433filmic_agx_compress_negatives(
const dt_aligned_pixel_simd_t pix,
const dt_aligned_pixel_simd_t luma_coeffs)
2440 const float input_y = pix[0] * luma_coeffs[0] + pix[1] * luma_coeffs[1] + pix[2] * luma_coeffs[2];
2441 const float max_rgb = fmaxf(fmaxf(pix[0], pix[1]), pix[2]);
2442 const float min_rgb = fminf(fminf(pix[0], pix[1]), pix[2]);
2444 const dt_aligned_pixel_simd_t opponent =
dt_simd_set1(max_rgb) - pix;
2445 const float opponent_y = opponent[0] * luma_coeffs[0] + opponent[1] * luma_coeffs[1] + opponent[2] * luma_coeffs[2];
2446 const float max_opponent = fmaxf(fmaxf(opponent[0], opponent[1]), opponent[2]);
2447 const float y_compensated = max_opponent - opponent_y + input_y;
2449 const float offset = fmaxf(-min_rgb, 0.f);
2450 const dt_aligned_pixel_simd_t shifted = pix +
dt_simd_set1(offset);
2451 const float max_shifted = fmaxf(fmaxf(shifted[0], shifted[1]), shifted[2]);
2452 const dt_aligned_pixel_simd_t opponent_shifted =
dt_simd_set1(max_shifted) - shifted;
2453 const float max_opponent_shifted
2454 = fmaxf(fmaxf(opponent_shifted[0], opponent_shifted[1]), opponent_shifted[2]);
2455 const float y_opponent_shifted = opponent_shifted[0] * luma_coeffs[0] + opponent_shifted[1] * luma_coeffs[1]
2456 + opponent_shifted[2] * luma_coeffs[2];
2458 = shifted[0] * luma_coeffs[0] + shifted[1] * luma_coeffs[1] + shifted[2] * luma_coeffs[2];
2459 y_new += max_opponent_shifted - y_opponent_shifted;
2461 const float ratio = (y_new > y_compensated && y_new > 1e-6f) ? y_compensated / y_new : 1.f;
2466static inline void filmic_agx(
const float *
const restrict in,
float *
const restrict
out,
2471 const size_t height,
const size_t ch,
const float display_black,
2472 const float display_white)
2480 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
2481 export_output_matrix, work_profile, export_profile);
2492 const dt_aligned_pixel_simd_t inset0 = dt_colormatrix_row_to_simd(inset_t, 0);
2493 const dt_aligned_pixel_simd_t inset1 = dt_colormatrix_row_to_simd(inset_t, 1);
2494 const dt_aligned_pixel_simd_t inset2 = dt_colormatrix_row_to_simd(inset_t, 2);
2495 const dt_aligned_pixel_simd_t outset0 = dt_colormatrix_row_to_simd(outset_t, 0);
2496 const dt_aligned_pixel_simd_t outset1 = dt_colormatrix_row_to_simd(outset_t, 1);
2497 const dt_aligned_pixel_simd_t outset2 = dt_colormatrix_row_to_simd(outset_t, 2);
2499 const dt_aligned_pixel_simd_t luma_coeffs = { work_profile->
matrix_in[1][0], work_profile->
matrix_in[1][1],
2506 dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2507 for(
size_t c = 0; c < 3; c++) pix_in[c] = isnan(pix_in[c]) ? 0.f :
CLAMPF(pix_in[c], -1e6f, 1e6f);
2508 const dt_aligned_pixel_simd_t compressed = filmic_agx_compress_negatives(pix_in, luma_coeffs);
2512 const dt_aligned_pixel_simd_t Ych_original = pipe_RGB_to_Ych_simd(compressed, simd_matrices.
input[0],
2513 simd_matrices.
input[1], simd_matrices.
input[2]);
2515 dt_aligned_pixel_simd_t rendering = dt_mat3x4_mul_vec4(compressed, inset0, inset1, inset2);
2516 rendering = RGB_tone_mapping_v4_simd(rendering, data, spline);
2517 const dt_aligned_pixel_simd_t pix_out = dt_mat3x4_mul_vec4(rendering, outset0, outset1, outset2);
2519 dt_aligned_pixel_simd_t Ych_final = pipe_RGB_to_Ych_simd(pix_out, simd_matrices.
input[0],
2520 simd_matrices.
input[1], simd_matrices.
input[2]);
2522 const float chroma_final = fminf(Ych_original[1], Ych_final[1]);
2538 const float r_mix = beta_hue * Ych_original[1] * Ych_original[2]
2539 + (1.f - beta_hue) * chroma_final * Ych_final[2];
2540 const float g_mix = beta_hue * Ych_original[1] * Ych_original[3]
2541 + (1.f - beta_hue) * chroma_final * Ych_final[3];
2542 const float norm_mix = dt_fast_hypotf(g_mix, r_mix);
2543 dt_aligned_pixel_simd_t Ych_reference = Ych_original;
2544 Ych_reference[2] = (norm_mix > 1e-9f) ? r_mix / norm_mix : Ych_original[2];
2545 Ych_reference[3] = (norm_mix > 1e-9f) ? g_mix / norm_mix : Ych_original[3];
2546 Ych_final[1] = chroma_final;
2548 dt_store_simd_nontemporal(
out +
k,
2549 gamut_mapping_simd(Ych_final, Ych_reference, output_matrix,
2550 simd_matrices.
input[0], simd_matrices.
input[1], simd_matrices.
input[2],
2552 export_output_matrix,
2555 display_black, display_white, 0.f, use_output_profile));
2562static inline void display_mask(
const float *
const restrict mask,
float *
const restrict
out,
2575static inline void compute_ratios(
const float *
const restrict in,
float *
const restrict norms,
2576 float *
const restrict ratios,
2578 const int variant,
const size_t width,
const size_t height)
2583 const dt_aligned_pixel_simd_t pix_in = dt_load_simd_aligned(in +
k);
2584 const float norm = fmaxf(get_pixel_norm_simd(pix_in, variant, work_profile),
NORM_MIN);
2585 norms[
k / 4] = norm;
2586 dt_store_simd_nontemporal(ratios +
k, pix_in /
dt_simd_set1(norm));
2593static inline void restore_ratios(
float *
const restrict ratios,
const float *
const restrict norms,
2599 dt_aligned_pixel_simd_t ratio = dt_load_simd_aligned(ratios + 4 *
k);
2600 const float norm = norms[
k];
2605 dt_store_simd_nontemporal(ratios + 4 *
k, ratio);
2623 && !isnan(softproof_profile->
matrix_out[0][0]))
2624 return softproof_profile;
2632 const int scales =
get_scales(pipe, roi_in, piece);
2633 const int max_filter_radius = (1 << scales);
2637 tiling->factor_cl = 9.0f;
2640 tiling->maxbuf_cl = 1.0f;
2642 tiling->overlap = max_filter_radius;
2650 const void *
const restrict ivoid,
2651 void *
const restrict
ovoid)
2659 const size_t ch = 4;
2670 float *restrict in = (
float *)ivoid;
2671 float *
const restrict
out = (
float *)
ovoid;
2695 if(recover_highlights &&
IS_NULL_PTR(reconstructed))
2750 data, piece, roi_in, roi_out))
2775 const float white_display = powf(data->spline.y[4], data->
output_power);
2776 const float black_display = powf(data->spline.y[0], data->
output_power);
2782 filmic_agx(in,
out, work_profile, export_profile, data, data->spline, roi_out->
width,
2783 roi_out->
height,
ch, black_display, white_display);
2787 filmic_v5(in,
out, work_profile, export_profile, data, data->spline, roi_out->
width,
2788 roi_out->
height,
ch, black_display, white_display);
2832 const int devid = pipe->
devid;
2838 const int scales =
get_scales(pipe, roi_in, piece);
2851 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
2862 if(err != CL_SUCCESS)
goto error;
2880 for(
int s = 0; s < scales; ++s)
2902 const int mult = 1 << s;
2905 const int clamp_lf = 1;
2908 .yoffset = 0, .yfactor = 1,
2909 .cellsize = 4 *
sizeof(float), .overhead = 0,
2910 .sizex = 1 << 16, .sizey = 1 };
2912 hblocksize = hlocopt.
sizex;
2919 const size_t horizontal_local[3] = { hblocksize, 1, 1 };
2927 (hblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
2929 horizontal_sizes, horizontal_local);
2941 if(err != CL_SUCCESS)
goto error;
2945 .yoffset = 2 * mult, .yfactor = 1,
2946 .cellsize = 4 *
sizeof(float), .overhead = 0,
2947 .sizex = 1, .sizey = 1 << 16 };
2949 vblocksize = vlocopt.
sizey;
2956 const size_t vertical_local[3] = { 1, vblocksize, 1 };
2964 (vblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
2966 vertical_sizes, vertical_local);
2978 if(err != CL_SUCCESS)
goto error;
2988 if(err != CL_SUCCESS)
goto error;
2991 size_t origin[] = { 0, 0, 0 };
2993 if(err != CL_SUCCESS)
goto error;
2996 const int blur_size = 1;
2997 const int clamp_hf = 0;
3005 if(err != CL_SUCCESS)
goto error;
3014 if(err != CL_SUCCESS)
goto error;
3034 if(err != CL_SUCCESS)
goto error;
3055 const int devid = pipe->
devid;
3062 cl_mem inpainted = NULL;
3063 cl_mem reconstructed = NULL;
3065 cl_mem ratios = NULL;
3066 cl_mem norms = NULL;
3071 const int use_work_profile = (
IS_NULL_PTR(work_profile)) ? 0 : 1;
3079 const int use_output_profile = filmic_v4_prepare_matrices(input_matrix, output_matrix, export_input_matrix,
3080 export_output_matrix, work_profile, export_profile);
3085 float input_matrix_3x4[12];
3086 float output_matrix_3x4[12];
3092 cl_mem export_input_matrix_cl = NULL;
3093 cl_mem export_output_matrix_cl = NULL;
3096 cl_mem inset_matrix_cl = NULL;
3097 cl_mem outset_matrix_cl = NULL;
3098 float luma_coeffs[4] = { work_profile->
matrix_in[1][0], work_profile->
matrix_in[1][1],
3105 float inset_3x4[12];
3106 float outset_3x4[12];
3113 cl_mem dev_profile_info = NULL;
3114 cl_mem dev_profile_lut = NULL;
3116 cl_float *profile_lut_cl = NULL;
3118 cl_mem clipped = NULL;
3121 &dev_profile_info, &dev_profile_lut);
3122 if(err != CL_SUCCESS)
goto error;
3124 if(use_output_profile)
3126 float export_input_matrix_3x4[12];
3127 float export_output_matrix_3x4[12];
3137 uint32_t is_clipped = 0;
3140 if(err != CL_SUCCESS)
goto error;
3152 if(err != CL_SUCCESS)
goto error;
3156 if(err != CL_SUCCESS)
goto error;
3187 const float noise_level =
d->noise_level / scale;
3198 if(err != CL_SUCCESS)
goto error;
3203 if(err != CL_SUCCESS)
goto error;
3207 if(
d->high_quality_reconstruction > 0)
3214 for(
int i = 0;
i <
d->high_quality_reconstruction;
i++)
3224 if(err != CL_SUCCESS)
goto error;
3228 if(err != CL_SUCCESS)
goto error;
3237 if(err != CL_SUCCESS)
goto error;
3255 const float white_display = powf(spline.
y[4],
d->output_power);
3256 const float black_display = powf(spline.
y[0],
d->output_power);
3296 if(err != CL_SUCCESS)
goto error;
3342 if(err != CL_SUCCESS)
goto error;
3382 const float grey = get_pixel_norm(self->
picked_color,
p->preserve_color, work_profile) / 2.0f;
3384 const float prev_grey =
p->grey_point_source;
3385 p->grey_point_source = CLAMP(100.f * grey, 0.001f, 100.0f);
3386 const float grey_var = log2f(prev_grey /
p->grey_point_source);
3387 p->black_point_source =
p->black_point_source - grey_var;
3388 p->white_point_source =
p->white_point_source + grey_var;
3389 p->output_power = logf(
p->grey_point_target / 100.0f)
3390 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3399 gtk_widget_queue_draw(self->
widget);
3413 float EVmin = CLAMP(log2f(black / (
p->grey_point_source / 100.0f)), -16.0f, -1.0f);
3414 EVmin *= (1.0f +
p->security_factor / 100.0f);
3416 p->black_point_source = fmaxf(EVmin, -16.0f);
3417 p->output_power = logf(
p->grey_point_target / 100.0f)
3418 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3425 gtk_widget_queue_draw(self->
widget);
3440 float EVmax = CLAMP(log2f(white / (
p->grey_point_source / 100.0f)), 1.0f, 16.0f);
3441 EVmax *= (1.0f +
p->security_factor / 100.0f);
3443 p->white_point_source = EVmax;
3444 p->output_power = logf(
p->grey_point_target / 100.0f)
3445 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3452 gtk_widget_queue_draw(self->
widget);
3465 const float grey = get_pixel_norm(self->
picked_color,
p->preserve_color, work_profile) / 2.0f;
3466 p->grey_point_source = CLAMP(100.f * grey, 0.001f, 100.0f);
3471 float EVmax = CLAMP(log2f(white / (
p->grey_point_source / 100.0f)), 1.0f, 16.0f);
3472 EVmax *= (1.0f +
p->security_factor / 100.0f);
3476 float EVmin = CLAMP(log2f(black / (
p->grey_point_source / 100.0f)), -16.0f, -1.0f);
3477 EVmin *= (1.0f +
p->security_factor / 100.0f);
3479 p->black_point_source = fmaxf(EVmin, -16.0f);
3480 p->white_point_source = EVmax;
3481 p->output_power = logf(
p->grey_point_target / 100.0f)
3482 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3491 gtk_widget_queue_draw(self->
widget);
3505 const float *
const restrict in = (
const float *)
i;
3507 float min_Y = INFINITY;
3508 float max_RGB = 0.0f;
3511 for(
size_t k = 0;
k < (size_t)roi_out->
width * roi_out->
height * 4;
k += 4)
3515 work_profile->unbounded_coeffs_in, work_profile->
lutsize,
3518 if(isfinite(
XYZ[1]))
3519 min_Y = fminf(min_Y,
XYZ[1]);
3521 const float pixel_max = fmaxf(in[
k], fmaxf(in[
k + 1], in[
k + 2]));
3522 if(isfinite(pixel_max))
3523 max_RGB = fmaxf(max_RGB, pixel_max);
3526 if(!isfinite(min_Y) || !isfinite(max_RGB))
return;
3528 const float grey =
p->grey_point_source / 100.0f;
3529 const float white = fmaxf(max_RGB,
NORM_MIN);
3530 const float black = fmaxf(min_Y,
NORM_MIN);
3532 float EVmax = CLAMP(log2f(white / grey), 1.0f, 16.0f);
3533 EVmax *= (1.0f +
p->security_factor / 100.0f);
3535 float EVmin = CLAMP(log2f(black / grey), -16.0f, -1.0f);
3536 EVmin *= (1.0f +
p->security_factor / 100.0f);
3538 p->black_point_source = fmaxf(EVmin, -16.0f);
3539 p->white_point_source = EVmax;
3540 p->output_power = logf(
p->grey_point_target / 100.0f)
3541 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
3548 (
void *)picker, (
void *)pipe,
3555 if(picker ==
g->grey_point_source)
3557 else if(picker ==
g->black_point_source)
3559 else if(picker ==
g->white_point_source)
3561 else if(picker ==
g->auto_button)
3569 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
off),
TRUE);
3576 g->show_mask = !(
g->show_mask);
3581 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->show_highlight_mask),
g->show_mask);
3596 const float transition_x,
const float transition_y,
3597 const float slope,
const float power)
3599 const float projected_rise = slope * fmaxf(1e-6f, limit_x - transition_x);
3600 const float actual_rise = fmaxf(1e-6f, limit_y - transition_y);
3601 const float base = fmaxf(1e-6f, powf(actual_rise, -power) - powf(projected_rise, -power));
3602 return fminf(1e9f, powf(base, -1.f / power));
3610 float grey_display = 0.4638f;
3611 gboolean clamping =
FALSE;
3616 grey_display = powf(CLAMP(
p->grey_point_target,
p->black_point_target,
p->white_point_target) / 100.0f,
3617 1.0f / (
p->output_power));
3622 grey_display = powf(0.1845f, 1.0f / (
p->output_power));
3625 const float white_source =
p->white_point_source;
3626 const float black_source =
p->black_point_source;
3627 const float dynamic_range = white_source - black_source;
3630 const float black_log = 0.0f;
3631 const float grey_log = fabsf(
p->black_point_source) / dynamic_range;
3632 const float white_log = 1.0f;
3635 float black_display, white_display;
3643 black_display = CLAMP(
p->black_point_target, 0.0f,
p->grey_point_target) / 100.0f;
3644 white_display = fmaxf(
p->white_point_target,
p->grey_point_target) / 100.0f;
3649 black_display = powf(CLAMP(
p->black_point_target, 0.0f,
p->grey_point_target) / 100.0f,
3650 1.0f / (
p->output_power));
3652 = powf(fmaxf(
p->white_point_target,
p->grey_point_target) / 100.0f, 1.0f / (
p->output_power));
3655 float toe_log, shoulder_log, toe_display, shoulder_display, contrast;
3656 float balance = CLAMP(
p->balance, -50.0f, 50.0f) / 100.0f;
3659 float latitude = CLAMP(
p->latitude, 0.0f, 100.0f) / 100.0f * dynamic_range;
3660 contrast = CLAMP(
p->contrast, 1.00001f, 6.0f);
3664 toe_log = grey_log - latitude / dynamic_range * fabsf(black_source / dynamic_range);
3665 shoulder_log = grey_log + latitude / dynamic_range * fabsf(white_source / dynamic_range);
3668 float linear_intercept = grey_display - (contrast * grey_log);
3671 toe_display = (toe_log * contrast + linear_intercept);
3672 shoulder_display = (shoulder_log * contrast + linear_intercept);
3675 const float norm = sqrtf(contrast * contrast + 1.0f);
3678 const float coeff = -((2.0f * latitude) / dynamic_range) * balance;
3680 toe_display +=
coeff * contrast / norm;
3681 shoulder_display +=
coeff * contrast / norm;
3682 toe_log +=
coeff / norm;
3683 shoulder_log +=
coeff / norm;
3709 spline->
x[0] = black_log;
3710 spline->
x[1] = toe_log;
3711 spline->
x[2] = grey_log;
3712 spline->
x[3] = shoulder_log;
3713 spline->
x[4] = white_log;
3715 spline->
y[0] = black_display;
3716 spline->
y[1] = toe_display;
3717 spline->
y[2] = grey_display;
3718 spline->
y[3] = shoulder_display;
3719 spline->
y[4] = white_display;
3724 spline->
type[0] =
p->shadows;
3725 spline->
type[1] =
p->highlights;
3732 const double Tl = spline->
x[1];
3733 const double Tl2 = Tl * Tl;
3734 const double Tl3 = Tl2 * Tl;
3735 const double Tl4 = Tl3 * Tl;
3737 const double Sl = spline->
x[3];
3738 const double Sl2 = Sl * Sl;
3739 const double Sl3 = Sl2 * Sl;
3740 const double Sl4 = Sl3 * Sl;
3750 spline->
M2[2] = contrast;
3751 spline->
M1[2] = spline->
y[1] - spline->
M2[2] * spline->
x[1];
3752 spline->
M3[2] = 0.f;
3753 spline->
M4[2] = 0.f;
3754 spline->
M5[2] = 0.f;
3772 const float sigmoid_toe_power = 1.5f;
3773 const float sigmoid_slope = spline->
M2[2];
3779 spline->
M3[2] = spline->
y[0];
3780 spline->
M4[2] = spline->
y[4];
3788 const float tx = spline->
x[1];
3789 const float ty = spline->
y[1];
3790 const float y0 = spline->
y[0];
3791 const float dx = fmaxf(1e-6f, tx);
3792 const float dy = fmaxf(1e-6f, ty - y0);
3793 spline->
M1[0] = -
filmic_sigmoid_scale(1.f, 1.f - y0, 1.f - tx, 1.f - ty, sigmoid_slope, sigmoid_toe_power);
3794 spline->
M2[0] = sigmoid_toe_power;
3795 spline->
M4[0] = sigmoid_slope * dx / dy;
3796 spline->
M3[0] = dy / powf(dx, spline->
M4[0]);
3797 spline->
M5[0] = (dy / dx > sigmoid_slope) ? 1.f : 0.f;
3804 Tl4, Tl3, Tl2, Tl, 1.,
3805 4. * Tl3, 3. * Tl2, 2. * Tl, 1., 0.,
3806 12. * Tl2, 6. * Tl, 2., 0., 0. };
3808 double b0[
ORDER_4] = { spline->
y[0], 0., spline->
y[1], spline->
M2[2], 0. };
3812 spline->
M5[0] = b0[0];
3813 spline->
M4[0] = b0[1];
3814 spline->
M3[0] = b0[2];
3815 spline->
M2[0] = b0[3];
3816 spline->
M1[0] = b0[4];
3823 3. * Tl2, 2. * Tl, 1., 0.,
3824 6. * Tl, 2., 0., 0. };
3826 double b0[
ORDER_3] = { spline->
y[0], spline->
y[1], spline->
M2[2], 0. };
3830 spline->
M5[0] = 0.0f;
3831 spline->
M4[0] = b0[0];
3832 spline->
M3[0] = b0[1];
3833 spline->
M2[0] = b0[2];
3834 spline->
M1[0] = b0[3];
3838 const float P1[2] = { black_log, black_display };
3839 const float P0[2] = { toe_log, toe_display };
3840 const float x = P0[0] - P1[0];
3841 const float y = P0[1] - P1[1];
3842 const float g = contrast;
3843 const float b =
g / (2.f * y) + (sqrtf(sqf(
x *
g / y + 1.f) - 4.f) - 1.f) / (2.f *
x);
3844 const float c = y /
g * (b * sqf(
x) +
x) / (b * sqf(
x) +
x - (y /
g));
3845 const float a = c *
g;
3849 spline->
M4[0] = toe_display;
3862 const float sx = spline->
x[3];
3863 const float sy = spline->
y[3];
3864 const float y4 = spline->
y[4];
3865 const float dx = fmaxf(1e-6f, 1.f - sx);
3866 const float dy = fmaxf(1e-6f, y4 - sy);
3867 spline->
M4[1] = sigmoid_slope * dx / dy;
3868 spline->
M3[1] = dy / powf(dx, spline->
M4[1]);
3869 spline->
M5[1] = 1.f;
3876 3. * Sl2, 2. * Sl, 1., 0.,
3877 6. * Sl, 2., 0., 0. };
3879 double b1[
ORDER_3] = { spline->
y[4], spline->
y[3], spline->
M2[2], 0. };
3883 spline->
M5[1] = 0.0f;
3884 spline->
M4[1] = b1[0];
3885 spline->
M3[1] = b1[1];
3886 spline->
M2[1] = b1[2];
3887 spline->
M1[1] = b1[3];
3894 Sl4, Sl3, Sl2, Sl, 1.,
3895 4. * Sl3, 3. * Sl2, 2. * Sl, 1., 0.,
3896 12. * Sl2, 6. * Sl, 2., 0., 0. };
3898 double b1[
ORDER_4] = { spline->
y[4], 0., spline->
y[3], spline->
M2[2], 0. };
3902 spline->
M5[1] = b1[0];
3903 spline->
M4[1] = b1[1];
3904 spline->
M3[1] = b1[2];
3905 spline->
M2[1] = b1[3];
3906 spline->
M1[1] = b1[4];
3910 const float P1[2] = { white_log, white_display };
3911 const float P0[2] = { shoulder_log, shoulder_display };
3912 const float x = P1[0] - P0[0];
3913 const float y = P1[1] - P0[1];
3914 const float g = contrast;
3915 const float b =
g / (2.f * y) + (sqrtf(sqf(
x *
g / y + 1.f) - 4.f) - 1.f) / (2.f *
x);
3916 const float c = y /
g * (b * sqf(
x) +
x) / (b * sqf(
x) +
x - (y /
g));
3917 const float a = c *
g;
3921 spline->
M4[1] = shoulder_display;
3933 float grey_source = 0.1845f, grey_display = 0.4638f;
3937 grey_source =
p->grey_point_source / 100.0f;
3938 grey_display = powf(
p->grey_point_target / 100.0f, 1.0f / (
p->output_power));
3943 grey_source = 0.1845f;
3944 grey_display = powf(0.1845f, 1.0f / (
p->output_power));
3948 const float white_source =
p->white_point_source;
3949 const float black_source =
p->black_point_source;
3950 const float dynamic_range = white_source - black_source;
3953 const float grey_log = fabsf(
p->black_point_source) / dynamic_range;
3956 float contrast =
p->contrast;
3961 contrast = 1.0001f * grey_display / grey_log;
3965 d->dynamic_range = dynamic_range;
3966 d->black_source = black_source;
3967 d->grey_source = grey_source;
3968 d->output_power =
p->output_power;
3969 d->contrast = contrast;
3970 d->version =
p->version;
3971 d->spline_version =
p->spline_version;
3972 d->preserve_color =
p->preserve_color;
3973 d->high_quality_reconstruction =
p->high_quality_reconstruction;
3974 d->noise_level =
p->noise_level;
3982 memset(
d->softproof_filename, 0,
sizeof(
d->softproof_filename));
3987 sizeof(
d->softproof_filename));
3998 d->saturation =
p->saturation / 100.0f;
4000 d->saturation = (2.0f *
p->saturation / 100.0f + 1.0f);
4015 const float agx_axis =
CLAMPF(
p->saturation / 100.0f, -1.f, 1.f);
4016 d->agx_beta_hue = 0.5f * (agx_axis + 1.f);
4018 d->sigma_toe = powf(
d->spline.latitude_min / 3.0f, 2.0f);
4019 d->sigma_shoulder = powf((1.0f -
d->spline.latitude_max) / 3.0f, 2.0f);
4021 d->reconstruct_threshold = powf(2.0f, white_source +
p->reconstruct_threshold) * grey_source;
4022 d->reconstruct_feather = exp2f(12.f /
p->reconstruct_feather);
4025 d->normalize =
d->reconstruct_feather /
d->reconstruct_threshold;
4026 d->reconstruct_structure_vs_texture = (
p->reconstruct_structure_vs_texture / 100.0f + 1.f) / 2.f;
4027 d->reconstruct_bloom_vs_details = (
p->reconstruct_bloom_vs_details / 100.0f + 1.f) / 2.f;
4028 d->reconstruct_grey_vs_color = (
p->reconstruct_grey_vs_color / 100.0f + 1.f) / 2.f;
4038 gint mask_was_shown =
g->show_mask;
4040 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->show_highlight_mask),
FALSE);
4072 float shoulder = 0.0f;
4089 &
p->latitude, &
p->balance);
4103 g->gui_show_labels =
dt_conf_get_int(
"plugins/darkroom/filmicrgb/graph_show_labels");
4105 g->gui_sizes_inited =
FALSE;
4109 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->auto_hardness),
p->auto_hardness);
4110 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->custom_grey),
p->custom_grey);
4121 d->white_point_source =
module->so->get_f("white_point_source")->Float.Default;
4122 d->output_power =
module->so->get_f("output_power")->Float.Default;
4137 d->white_point_source = exposure + 2.45f;
4138 d->black_point_source =
d->white_point_source - 12.f;
4139 d->output_power = logf(
d->grey_point_target / 100.0f)
4140 / logf(-
d->black_point_source / (
d->white_point_source -
d->black_point_source));
4142 module->workflow_enabled = TRUE;
4144 dt_iop_fmt_log(module,
"reload_defaults: class=%s needs_rawprepare=%d -> workflow_enabled=%d white=%.3f black=%.3f",
4147 d->white_point_source,
d->black_point_source);
4153 const int program = 22;
4168 const int wavelets = 35;
4205 double destination_y, gboolean show_head)
4207 cairo_move_to(cr, origin_x, origin_y);
4208 cairo_line_to(cr, destination_x, destination_y);
4214 const float angle_arrow = 45.f / 360.f *
M_PI;
4215 const float angle_trunk = atan2f((destination_y - origin_y), (destination_x - origin_x));
4218 const float x_1 = destination_x + radius / sinf(angle_arrow + angle_trunk);
4219 const float y_1 = destination_y + radius / cosf(angle_arrow + angle_trunk);
4221 const float x_2 = destination_x - radius / sinf(-angle_arrow + angle_trunk);
4222 const float y_2 = destination_y - radius / cosf(-angle_arrow + angle_trunk);
4224 cairo_move_to(cr, x_1, y_1);
4225 cairo_line_to(cr, destination_x, destination_y);
4226 cairo_line_to(cr, x_2, y_2);
4234 if(!
g->gui_sizes_inited)
return;
4249 cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha);
4254 cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha * 0.5);
4264 const float scale = 0.85;
4265 cairo_scale(cr, scale, scale);
4266 button->
icon(cr, -scale * button->
w / 2., -scale * button->
h / 2., scale * button->
w, scale * button->
h, 0, NULL);
4279 gtk_widget_get_allocation(widget, &
g->allocation);
4281 cairo_surface_t *cst =
4283 PangoFontDescription *desc =
4285 cairo_t *cr = cairo_create(cst);
4286 PangoLayout *layout = pango_cairo_create_layout(cr);
4288 pango_layout_set_font_description(layout, desc);
4290 g->context = gtk_widget_get_style_context(widget);
4295 const gint font_size = pango_font_description_get_size(desc);
4296 pango_font_description_set_size(desc, 0.95 * font_size);
4297 pango_layout_set_font_description(layout, desc);
4300 g_strlcpy(text,
"X",
sizeof(text));
4301 pango_layout_set_text(layout, text, -1);
4302 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4303 g->line_height =
g->ink.height;
4306 g_strlcpy(text,
"-",
sizeof(text));
4307 pango_layout_set_text(layout, text, -1);
4308 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4309 g->sign_width =
g->ink.width / 2.0;
4312 g_strlcpy(text,
"0",
sizeof(text));
4313 pango_layout_set_text(layout, text, -1);
4314 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4315 g->zero_width =
g->ink.width;
4321 float margin_bottom;
4322 if(
g->gui_show_labels)
4325 margin_left = 3. *
g->zero_width + 2. *
g->inset;
4326 margin_bottom = 2. *
g->line_height + 4. *
g->inset;
4330 margin_left =
g->inset;
4331 margin_bottom =
g->inset;
4334 const float margin_top = 2. *
g->line_height +
g->inset;
4337 g->graph_width =
g->allocation.width - margin_right - margin_left;
4338 g->graph_height =
g->allocation.height - margin_bottom - margin_top;
4340 gtk_render_background(
g->context, cr, 0, 0,
g->allocation.width,
g->allocation.height);
4346 g->buttons[
i].right =
g->allocation.width;
4350 g->buttons[
i].w =
g->buttons[
i].right -
g->buttons[
i].left;
4351 g->buttons[
i].h =
g->buttons[
i].bottom -
g->buttons[
i].top;
4352 g->buttons[
i].state = GTK_STATE_FLAG_NORMAL;
4355 g->gui_sizes_inited =
TRUE;
4365 const float grey =
p->grey_point_source / 100.f;
4366 const float DR =
p->white_point_source -
p->black_point_source;
4369 cairo_translate(cr, margin_left, margin_top);
4371 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
4374 pango_font_description_set_size(desc, font_size);
4375 pango_layout_set_font_description(layout, desc);
4377 g_strlcpy(text, _(
"look only"),
sizeof(text));
4379 g_strlcpy(text, _(
"look + mapping (lin)"),
sizeof(text));
4381 g_strlcpy(text, _(
"look + mapping (log)"),
sizeof(text));
4383 g_strlcpy(text, _(
"dynamic range mapping"),
sizeof(text));
4385 pango_layout_set_text(layout, text, -1);
4386 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4390 cairo_rectangle(cr,
g->allocation.width - margin_left -
g->ink.width -
g->ink.x - 2. *
g->inset,
4391 -
g->line_height -
g->inset - 0.5 *
g->ink.height -
g->ink.y -
g->inset,
4392 g->ink.width + 3. *
g->inset,
g->ink.height + 2. *
g->inset);
4397 cairo_move_to(cr,
g->allocation.width - margin_left -
g->ink.width -
g->ink.x -
g->inset,
4398 -
g->line_height -
g->inset - 0.5 *
g->ink.height -
g->ink.y);
4399 pango_cairo_show_layout(cr, layout);
4403 pango_font_description_set_size(desc, 0.95 * font_size);
4404 pango_layout_set_font_description(layout, desc);
4410 cairo_rectangle(cr, 0, 0,
g->graph_width,
g->graph_height);
4412 cairo_fill_preserve(cr);
4422 cairo_scale(cr, 1., -1.);
4423 cairo_translate(cr, 0., -
g->graph_height);
4434 cairo_move_to(cr, 0,
g->graph_height);
4435 cairo_line_to(cr,
g->graph_width, 0);
4441 const float saturation = (2.0f *
p->saturation / 100.0f + 1.0f);
4442 const float sigma_toe = powf(
g->spline.latitude_min / 3.0f, 2.0f);
4443 const float sigma_shoulder = powf((1.0f -
g->spline.latitude_max) / 3.0f, 2.0f);
4445 cairo_set_source_rgb(cr, .5, .5, .5);
4455 cairo_move_to(cr, 0,
4456 g->graph_height * (1.0 - filmic_desaturate_v1(0.0f, sigma_toe, sigma_shoulder, saturation)));
4457 for(
int k = 1;
k < 256;
k++)
4459 float x =
k / 255.0;
4460 const float y = filmic_desaturate_v1(
x, sigma_toe, sigma_shoulder, saturation);
4467 cairo_line_to(cr,
x *
g->graph_width,
g->graph_height * (1.0 - y));
4472 cairo_move_to(cr, 0,
4473 g->graph_height * (1.0 - filmic_desaturate_v2(0.0f, sigma_toe, sigma_shoulder, saturation)));
4474 for(
int k = 1;
k < 256;
k++)
4476 float x =
k / 255.0;
4477 const float y = filmic_desaturate_v2(
x, sigma_toe, sigma_shoulder, saturation);
4484 cairo_line_to(cr,
x *
g->graph_width,
g->graph_height * (1.0 - y));
4490 float x_start = 0.f;
4496 float y_start =
clamp_simd(filmic_spline(x_start,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
4497 g->spline.M5,
g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type));
4500 y_start = powf(y_start,
p->output_power);
4504 cairo_move_to(cr, 0,
g->graph_height * (1.0 - y_start));
4506 for(
int k = 1;
k < 256;
k++)
4510 float x = powf(
k / 255.0f, 2.4f);
4518 float y = filmic_spline(
value,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
g->spline.M5,
4519 g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type);
4527 const float margin = 1
E-5;
4528 if(y >
g->spline.y[4] + margin)
4531 cairo_set_source_rgb(cr, 0.75, .5, 0.);
4533 else if(y < g->spline.
y[0] - margin)
4536 cairo_set_source_rgb(cr, 0.75, .5, 0.);
4544 y = powf(y,
p->output_power);
4548 cairo_line_to(cr,
x *
g->graph_width,
g->graph_height * (1.0 - y));
4550 cairo_move_to(cr,
x *
g->graph_width,
g->graph_height * (1.0 - y));
4562 float x_grey =
g->spline.x[2];
4563 float y_grey =
g->spline.y[2];
4568 y_grey = powf(y_grey,
p->output_power);
4576 cairo_set_source_rgb(cr, 0.75, 0.5, 0.0);
4577 cairo_arc(cr, x_grey *
g->graph_width, (1.0 - y_grey) *
g->graph_height,
DT_PIXEL_APPLY_DPI(6), 0,
4583 float x_black = 0.f;
4584 float y_black = 0.f;
4586 float x_white = 1.f;
4587 float y_white = 1.f;
4589 const float central_slope = (
g->spline.y[3] -
g->spline.y[1]) *
g->graph_width / ((
g->spline.x[3] -
g->spline.x[1]) *
g->graph_height);
4590 const float central_slope_angle = atanf(central_slope) +
M_PI / 2.0f;
4592 for(
int k = 0;
k < 5;
k++)
4596 float x =
g->spline.x[
k];
4597 float y =
g->spline.y[
k];
4598 const float ymin =
g->spline.y[0];
4599 const float ymax =
g->spline.y[4];
4601 const float y_margin =
SAFETY_MARGIN * 1.1f * (ymax - ymin);
4602 gboolean red = (((
k == 1) && (y - ymin <= y_margin))
4603 || ((
k == 3) && (ymax - y <= y_margin)));
4604 float start_angle = 0.0f;
4605 float end_angle = 2.f *
M_PI;
4608 if(contrast_clamped)
4612 start_angle = central_slope_angle +
M_PI;
4613 end_angle = central_slope_angle;
4617 start_angle = central_slope_angle;
4618 end_angle = start_angle +
M_PI;
4625 y = powf(y,
p->output_power);
4645 if(red) cairo_set_source_rgb(cr, 0.8, 0.35, 0.35);
4648 cairo_arc(cr,
x *
g->graph_width, (1.0 - y) *
g->graph_height,
DT_PIXEL_APPLY_DPI(4), start_angle, end_angle);
4658 if(
g->gui_show_labels)
4661 const float x_legend_top =
g->graph_height + 0.5 *
g->line_height;
4665 snprintf(text,
sizeof(text),
"%.0f",
p->grey_point_target);
4666 pango_layout_set_text(layout, text, -1);
4667 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4668 cairo_move_to(cr, -2. *
g->inset -
g->ink.width -
g->ink.x,
4669 (1.0 - y_grey) *
g->graph_height - 0.5 *
g->ink.height -
g->ink.y);
4670 pango_cairo_show_layout(cr, layout);
4676 snprintf(text,
sizeof(text),
"%+.1f", 0.f);
4678 snprintf(text,
sizeof(text),
"%.0f",
p->grey_point_source);
4680 pango_layout_set_text(layout, text, -1);
4681 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4682 cairo_move_to(cr, x_grey *
g->graph_width - 0.5 *
g->ink.width -
g->ink.x, x_legend_top);
4683 pango_cairo_show_layout(cr, layout);
4688 snprintf(text,
sizeof(text),
"%.0f",
p->black_point_target);
4689 pango_layout_set_text(layout, text, -1);
4690 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4691 cairo_move_to(cr, -2. *
g->inset -
g->ink.width -
g->ink.x,
4692 (1.0 - y_black) *
g->graph_height - 0.5 *
g->ink.height -
g->ink.y);
4693 pango_cairo_show_layout(cr, layout);
4698 snprintf(text,
sizeof(text),
"%.0f",
p->white_point_target);
4699 pango_layout_set_text(layout, text, -1);
4700 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4701 cairo_move_to(cr, -2. *
g->inset -
g->ink.width -
g->ink.x,
4702 (1.0 - y_white) *
g->graph_height - 0.5 *
g->ink.height -
g->ink.y);
4703 pango_cairo_show_layout(cr, layout);
4709 snprintf(text,
sizeof(text),
"%+.1f",
p->black_point_source);
4711 snprintf(text,
sizeof(text),
"%.0f", exp2f(
p->black_point_source) *
p->grey_point_source);
4713 pango_layout_set_text(layout, text, -1);
4714 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4715 cairo_move_to(cr, x_black *
g->graph_width - 0.5 *
g->ink.width -
g->ink.x, x_legend_top);
4716 pango_cairo_show_layout(cr, layout);
4722 snprintf(text,
sizeof(text),
"%+.1f",
p->white_point_source);
4726 snprintf(text,
sizeof(text),
"%.0f \342\206\222", 100.f);
4728 snprintf(text,
sizeof(text),
"%.0f", exp2f(
p->white_point_source) *
p->grey_point_source);
4731 pango_layout_set_text(layout, text, -1);
4732 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4734 fminf(x_white, 1.f) *
g->graph_width - 0.5 *
g->ink.width -
g->ink.x
4735 + 2. * (x_white > 1.f) *
g->sign_width,
4737 pango_cairo_show_layout(cr, layout);
4746 PangoStyle backup = pango_font_description_get_style(desc);
4747 pango_font_description_set_style(desc, PANGO_STYLE_ITALIC);
4748 pango_layout_set_font_description(layout, desc);
4750 snprintf(text,
sizeof(text), _(
"(%.0f %%)"), exp2f(
p->white_point_source) *
p->grey_point_source);
4751 pango_layout_set_text(layout, text, -1);
4752 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4753 cairo_move_to(cr,
g->allocation.width -
g->ink.width -
g->ink.x - margin_left,
4754 g->graph_height + 3. *
g->inset +
g->line_height -
g->ink.y);
4755 pango_cairo_show_layout(cr, layout);
4759 pango_font_description_set_style(desc, backup);
4760 pango_layout_set_font_description(layout, desc);
4766 g_strlcpy(text, _(
"% display"),
sizeof(text));
4767 pango_layout_set_text(layout, text, -1);
4768 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4769 cairo_move_to(cr, -2. *
g->inset -
g->zero_width -
g->ink.x,
4770 -
g->line_height -
g->inset - 0.5 *
g->ink.height -
g->ink.y);
4771 pango_cairo_show_layout(cr, layout);
4778 g_strlcpy(text, _(
"EV scene"),
sizeof(text));
4782 g_strlcpy(text, _(
"% camera"),
sizeof(text));
4784 pango_layout_set_text(layout, text, -1);
4785 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4786 cairo_move_to(cr, 0.5 *
g->graph_width - 0.5 *
g->ink.width -
g->ink.x,
4787 g->graph_height + 3. *
g->inset +
g->line_height -
g->ink.y);
4788 pango_cairo_show_layout(cr, layout);
4795 cairo_identity_matrix(cr);
4801 const float display_DR = 12.f + log2f(
p->white_point_target / 100.f);
4803 const float y_display =
g->allocation.height / 3.f +
g->line_height;
4804 const float y_scene = 2. *
g->allocation.height / 3.f +
g->line_height;
4806 const float display_top = y_display -
g->line_height / 2;
4807 const float display_bottom = display_top +
g->line_height;
4809 const float scene_top = y_scene -
g->line_height / 2;
4810 const float scene_bottom = scene_top +
g->line_height;
4814 if(
g->gui_show_labels)
4818 g_strlcpy(text, _(
"display"),
sizeof(text));
4819 pango_layout_set_text(layout, text, -1);
4820 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4821 cairo_move_to(cr, 0., y_display - 0.5 *
g->ink.height -
g->ink.y);
4822 pango_cairo_show_layout(cr, layout);
4824 const float display_label_width =
g->ink.width;
4827 g_strlcpy(text, _(
"(%)"),
sizeof(text));
4828 pango_layout_set_text(layout, text, -1);
4829 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4830 cairo_move_to(cr, 0.5 * display_label_width - 0.5 *
g->ink.width -
g->ink.x,
4831 display_top - 4. *
g->inset -
g->ink.height -
g->ink.y);
4832 pango_cairo_show_layout(cr, layout);
4836 g_strlcpy(text, _(
"scene"),
sizeof(text));
4837 pango_layout_set_text(layout, text, -1);
4838 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4839 cairo_move_to(cr, 0., y_scene - 0.5 *
g->ink.height -
g->ink.y);
4840 pango_cairo_show_layout(cr, layout);
4842 const float scene_label_width =
g->ink.width;
4845 g_strlcpy(text, _(
"(EV)"),
sizeof(text));
4846 pango_layout_set_text(layout, text, -1);
4847 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
4848 cairo_move_to(cr, 0.5 * scene_label_width - 0.5 *
g->ink.width -
g->ink.x,
4849 scene_bottom + 2. *
g->inset + 0. *
g->ink.height +
g->ink.y);
4850 pango_cairo_show_layout(cr, layout);
4855 dt_cairo_draw_arrow(cr, fminf(scene_label_width, display_label_width) / 2.f, y_scene -
g->line_height,
4856 fminf(scene_label_width, display_label_width) / 2.f,
4857 y_display +
g->line_height +
g->inset,
TRUE);
4859 column_left = fmaxf(display_label_width, scene_label_width) +
g->inset;
4867 const float display_HL_EV = -log2f(
p->grey_point_target /
p->white_point_target);
4868 const float display_LL_EV = display_DR - display_HL_EV;
4869 const float display_real_black_EV
4870 = -fmaxf(log2f(
p->black_point_target /
p->grey_point_target),
4871 -11.685887601778058f + display_HL_EV - log2f(
p->white_point_target / 100.f));
4872 const float scene_HL_EV =
p->white_point_source;
4873 const float scene_LL_EV = -
p->black_point_source;
4876 const float max_DR = ceilf(fmaxf(display_HL_EV, scene_HL_EV)) + ceilf(fmaxf(display_LL_EV, scene_LL_EV));
4877 const float EV = (column_right) / max_DR;
4881 const float grey_EV = fmaxf(ceilf(display_HL_EV), ceilf(scene_HL_EV));
4885 const float display_black_x = grey_x - display_real_black_EV * EV;
4886 const float display_DR_start_x = grey_x - display_LL_EV * EV;
4887 const float display_white_x = grey_x + display_HL_EV * EV;
4889 const float scene_black_x = grey_x - scene_LL_EV * EV;
4890 const float scene_white_x = grey_x + scene_HL_EV * EV;
4891 const float scene_lat_bottom = grey_x + (
g->spline.x[1] -
g->spline.x[2]) * EV * DR;
4892 const float scene_lat_top = grey_x + (
g->spline.x[3] -
g->spline.x[2]) * EV * DR;
4900 float display_lat_bottom = filmic_spline(
g->spline.latitude_min,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
4901 g->spline.M5,
g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type);
4902 display_lat_bottom = powf(fmaxf(display_lat_bottom,
NORM_MIN),
p->output_power);
4905 display_lat_bottom = log2f(display_lat_bottom/ (
p->grey_point_target / 100.f));
4908 if(display_lat_bottom < 0.f)
4909 display_lat_bottom = fmaxf(display_lat_bottom, -display_real_black_EV);
4910 else if(display_lat_bottom > 0.f)
4911 display_lat_bottom = fminf(display_lat_bottom, display_HL_EV);
4914 display_lat_bottom = grey_x + display_lat_bottom * EV;
4917 float display_lat_top = filmic_spline(
g->spline.latitude_max,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
4918 g->spline.M5,
g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type);
4919 display_lat_top = powf(fmaxf(display_lat_top,
NORM_MIN),
p->output_power);
4922 display_lat_top = log2f(display_lat_top / (
p->grey_point_target / 100.f));
4925 if(display_lat_top < 0.f)
4926 display_lat_top = fmaxf(display_lat_top, -display_real_black_EV);
4927 else if(display_lat_top > 0.f)
4928 display_lat_top = fminf(display_lat_top, display_HL_EV);
4931 display_lat_top = grey_x + display_lat_top * EV;
4933 cairo_move_to(cr, scene_lat_bottom, scene_top);
4934 cairo_line_to(cr, scene_lat_top, scene_top);
4935 cairo_line_to(cr, display_lat_top, display_bottom);
4936 cairo_line_to(cr, display_lat_bottom, display_bottom);
4937 cairo_line_to(cr, scene_lat_bottom, scene_top);
4941 for(
int i = 0;
i < (int)ceilf(display_DR);
i++)
4944 const float shade = powf(exp2f(-11.f + (
float)
i), 1.f / 2.4f);
4945 cairo_set_source_rgb(cr, shade, shade, shade);
4946 cairo_rectangle(cr, display_DR_start_x +
i * EV, display_top, EV,
g->line_height);
4947 cairo_fill_preserve(cr);
4950 cairo_set_source_rgb(cr, 0.75, .5, 0.);
4956 cairo_move_to(cr, grey_x, display_bottom + 2. *
g->inset);
4957 cairo_line_to(cr, grey_x, display_top - 2. *
g->inset);
4962 for(
int i = floorf(
p->black_point_source);
i < ceilf(
p->white_point_source);
i++)
4966 const float shade = powf(0.1845f * exp2f((
float)
i), 1.f / 2.4f);
4967 const float x_temp = grey_x +
i * EV;
4968 cairo_set_source_rgb(cr, shade, shade, shade);
4969 cairo_rectangle(cr, x_temp, scene_top, EV,
g->line_height);
4970 cairo_fill_preserve(cr);
4973 cairo_set_source_rgb(cr, 0.75, .5, 0.);
4982 if((
float)
i >
p->black_point_source && (
float)i < p->white_point_source)
4985 const float normal_value = ((float)
i -
p->black_point_source) / DR;
4986 float y_temp = filmic_spline(normal_value,
g->spline.M1,
g->spline.M2,
g->spline.M3,
g->spline.M4,
4987 g->spline.M5,
g->spline.latitude_min,
g->spline.latitude_max,
g->spline.type);
4988 y_temp = powf(fmaxf(y_temp,
NORM_MIN),
p->output_power);
4991 y_temp = log2f(y_temp / (
p->grey_point_target / 100.f));
4995 y_temp = fmaxf(y_temp, -display_real_black_EV);
4996 else if(y_temp > 0.f)
4997 y_temp = fminf(y_temp, display_HL_EV);
5000 y_temp = grey_x + y_temp * EV;
5008 float x_temp = grey_x +
p->black_point_source * EV;
5009 float y_temp = grey_x - display_real_black_EV * EV;
5012 x_temp = grey_x +
p->white_point_source * EV;
5013 y_temp = grey_x + display_HL_EV * EV;
5019 cairo_move_to(cr, display_black_x, display_bottom);
5020 cairo_line_to(cr, display_black_x, display_top - 2. *
g->inset);
5024 cairo_move_to(cr, grey_x, display_bottom);
5025 cairo_line_to(cr, grey_x, display_top - 2. *
g->inset);
5029 cairo_move_to(cr, display_white_x, display_bottom);
5030 cairo_line_to(cr, display_white_x, display_top - 2. *
g->inset);
5034 cairo_move_to(cr, scene_black_x, scene_bottom + 2. *
g->inset);
5035 cairo_line_to(cr, scene_black_x, scene_top);
5039 cairo_move_to(cr, grey_x, scene_bottom + 2. *
g->inset);
5040 cairo_line_to(cr, grey_x, scene_top);
5044 cairo_move_to(cr, scene_white_x, scene_bottom + 2. *
g->inset);
5045 cairo_line_to(cr, scene_white_x, scene_top);
5052 snprintf(text,
sizeof(text),
"%+.1f",
p->black_point_source);
5053 pango_layout_set_text(layout, text, -1);
5054 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5055 cairo_move_to(cr, scene_black_x - 0.5 *
g->ink.width -
g->ink.x,
5056 scene_bottom + 2. *
g->inset + 0. *
g->ink.height +
g->ink.y);
5057 pango_cairo_show_layout(cr, layout);
5061 snprintf(text,
sizeof(text),
"%+.1f", 0.f);
5062 pango_layout_set_text(layout, text, -1);
5063 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5064 cairo_move_to(cr, grey_x - 0.5 *
g->ink.width -
g->ink.x,
5065 scene_bottom + 2. *
g->inset + 0. *
g->ink.height +
g->ink.y);
5066 pango_cairo_show_layout(cr, layout);
5070 snprintf(text,
sizeof(text),
"%+.1f",
p->white_point_source);
5071 pango_layout_set_text(layout, text, -1);
5072 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5073 cairo_move_to(cr, scene_white_x - 0.5 *
g->ink.width -
g->ink.x,
5074 scene_bottom + 2. *
g->inset + 0. *
g->ink.height +
g->ink.y);
5075 pango_cairo_show_layout(cr, layout);
5079 snprintf(text,
sizeof(text),
"%.0f",
p->black_point_target);
5080 pango_layout_set_text(layout, text, -1);
5081 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5082 cairo_move_to(cr, display_black_x - 0.5 *
g->ink.width -
g->ink.x,
5083 display_top - 4. *
g->inset -
g->ink.height -
g->ink.y);
5084 pango_cairo_show_layout(cr, layout);
5088 snprintf(text,
sizeof(text),
"%.0f",
p->grey_point_target);
5089 pango_layout_set_text(layout, text, -1);
5090 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5091 cairo_move_to(cr, grey_x - 0.5 *
g->ink.width -
g->ink.x,
5092 display_top - 4. *
g->inset -
g->ink.height -
g->ink.y);
5093 pango_cairo_show_layout(cr, layout);
5097 snprintf(text,
sizeof(text),
"%.0f",
p->white_point_target);
5098 pango_layout_set_text(layout, text, -1);
5099 pango_layout_get_pixel_extents(layout, &
g->ink, NULL);
5100 cairo_move_to(cr, display_white_x - 0.5 *
g->ink.width -
g->ink.x,
5101 display_top - 4. *
g->inset -
g->ink.height -
g->ink.y);
5102 pango_cairo_show_layout(cr, layout);
5107 pango_font_description_set_size(desc, font_size);
5108 pango_layout_set_font_description(layout, desc);
5111 cairo_set_source_surface(crf, cst, 0, 0);
5113 cairo_surface_destroy(cst);
5114 g_object_unref(layout);
5115 pango_font_description_free(desc);
5131 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS)
5137 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5146 else if(event->button == 1)
5157 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5163 g->gui_show_labels = !
g->gui_show_labels;
5164 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5165 dt_conf_set_int(
"plugins/darkroom/filmicrgb/graph_show_labels",
g->gui_show_labels);
5175 else if(event->button == 3)
5185 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5191 g->gui_show_labels = !
g->gui_show_labels;
5192 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5193 dt_conf_set_int(
"plugins/darkroom/filmicrgb/graph_show_labels",
g->gui_show_labels);
5213 g->gui_hover =
TRUE;
5214 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5227 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5237 if(!
g->gui_sizes_inited)
return FALSE;
5240 const float y =
event->y;
5241 const float x =
event->x;
5243 if(
x > 0. && x < g->allocation.width && y > 0. && y < g->allocation.height)
g->gui_hover =
TRUE;
5245 gint save_active_button =
g->active_button;
5250 gint found_something =
FALSE;
5254 if(
x >
g->buttons[
i].left && x < g->buttons[
i].right && y >
g->buttons[
i].top && y < g->buttons[
i].bottom)
5257 g->buttons[
i].mouse_hover =
TRUE;
5258 g->active_button =
i;
5259 found_something =
TRUE;
5264 g->buttons[
i].mouse_hover =
FALSE;
5274 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area), _(
"use the parameters below to set the nodes.\n"
5275 "the bright curve is the filmic tone mapping curve\n"
5276 "the dark curve is the desaturation curve."));
5280 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area), _(
"toggle axis labels and values display"));
5284 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area), _(
"cycle through graph views.\n"
5285 "left click: cycle forward.\n"
5286 "right click: cycle backward.\n"
5287 "double-click: reset to look view."));
5291 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area),
"");
5294 if(save_active_button !=
g->active_button) gtk_widget_queue_draw(GTK_WIDGET(
g->area));
5300 if(save_active_button !=
g->active_button) (GTK_WIDGET(
g->area));
5317 g->gui_show_labels =
TRUE;
5319 g->gui_sizes_inited =
FALSE;
5322 g->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
5323 gtk_widget_set_hexpand(GTK_WIDGET(
g->area),
TRUE);
5324 g_object_set_data(G_OBJECT(
g->area),
"iop-instance", self);
5326 gtk_widget_set_can_focus(GTK_WIDGET(
g->area),
TRUE);
5327 gtk_widget_add_events(GTK_WIDGET(
g->area), GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
5330 g_signal_connect(G_OBJECT(
g->area),
"button-press-event", G_CALLBACK(
area_button_press), self);
5331 g_signal_connect(G_OBJECT(
g->area),
"leave-notify-event", G_CALLBACK(
area_leave_notify), self);
5332 g_signal_connect(G_OBJECT(
g->area),
"enter-notify-event", G_CALLBACK(
area_enter_notify), self);
5333 g_signal_connect(G_OBJECT(
g->area),
"motion-notify-event", G_CALLBACK(
area_motion_notify), self);
5346 g->grey_point_source
5350 gtk_widget_set_tooltip_text(
g->grey_point_source,
5351 _(
"adjust to match the average luminance of the image's subject.\n"
5352 "the value entered here will then be remapped to 18.45%.\n"
5353 "decrease the value to increase the overall brightness."));
5356 g->white_point_source
5360 gtk_widget_set_tooltip_text(
g->white_point_source,
5361 _(
"number of stops between middle gray and pure white.\n"
5362 "this is a reading a lightmeter would give you on the scene.\n"
5363 "adjust so highlights clipping is avoided"));
5366 g->black_point_source
5370 gtk_widget_set_tooltip_text(
5371 g->black_point_source, _(
"number of stops between middle gray and pure black.\n"
5372 "this is a reading a lightmeter would give you on the scene.\n"
5373 "increase to get more contrast.\ndecrease to recover more details in low-lights."));
5379 gtk_widget_set_tooltip_text(
g->security_factor, _(
"symmetrically enlarge or shrink the computed dynamic range.\n"
5380 "useful to give a safety margin to extreme luminances."));
5386 gtk_box_pack_start(GTK_BOX(hbox),
g->auto_button,
FALSE,
FALSE, 0);
5388 gtk_widget_set_tooltip_text(
g->auto_button, _(
"try to optimize the settings with some statistical assumptions.\n"
5389 "this will fit the luminance range inside the histogram bounds.\n"
5390 "works better for landscapes and evenly-lit pictures\n"
5391 "but fails for high-keys, low-keys and high-ISO pictures.\n"
5392 "this is not an artificial intelligence, but a simple guess.\n"
5393 "ensure you understand its assumptions before using it."));
5400 gtk_widget_set_tooltip_text(
g->custom_grey, _(
"enable to input custom middle-gray values.\n"
5401 "this is not recommended in general.\n"
5402 "fix the global exposure in the exposure module instead.\n"
5403 "disable to use standard 18.45 %% middle gray."));
5413 gtk_widget_set_tooltip_text(
g->reconstruct_threshold,
5414 _(
"set the exposure threshold upon which\n"
5415 "clipped highlights get reconstructed.\n"
5416 "values are relative to the scene white point.\n"
5417 "0 EV means the threshold is the same as the scene white point.\n"
5418 "decrease to include more areas,\n"
5419 "increase to exclude more areas."));
5423 gtk_widget_set_tooltip_text(
g->reconstruct_feather,
5424 _(
"soften the transition between clipped highlights and valid pixels.\n"
5425 "decrease to make the transition harder and sharper,\n"
5426 "increase to make the transition softer and blurrier."));
5430 gtk_box_pack_start(GTK_BOX(hbox),
dt_ui_label_new(_(
"display highlight reconstruction mask")),
TRUE,
TRUE, 0);
5443 gtk_widget_set_tooltip_text(
g->reconstruct_structure_vs_texture,
5445 _(
"decide which reconstruction strategy to favor,\n"
5446 "between inpainting a smooth color gradient,\n"
5447 "or trying to recover the textured details.\n"
5448 "0% is an equal mix of both.\n"
5449 "increase if at least one RGB channel is not clipped.\n"
5450 "decrease if all RGB channels are clipped over large areas."));
5454 gtk_widget_set_tooltip_text(
g->reconstruct_bloom_vs_details,
5456 _(
"decide which reconstruction strategy to favor,\n"
5457 "between blooming highlights like film does,\n"
5458 "or trying to recover sharp details.\n"
5459 "0% is an equal mix of both.\n"
5460 "increase if you want more details.\n"
5461 "decrease if you want more blur."));
5466 gtk_widget_set_tooltip_text(
g->reconstruct_grey_vs_color,
5468 _(
"decide which reconstruction strategy to favor,\n"
5469 "between recovering monochromatic highlights,\n"
5470 "or trying to recover colorful highlights.\n"
5471 "0% is an equal mix of both.\n"
5472 "increase if you want more color.\n"
5473 "decrease if you see magenta or out-of-gamut highlights."));
5480 gtk_widget_set_tooltip_text(
g->high_quality_reconstruction,
5481 _(
"run extra passes of chromaticity reconstruction.\n"
5482 "more iterations means more color propagation from neighbourhood.\n"
5483 "this will be slower but will yield more neutral highlights.\n"
5484 "it also helps with difficult cases of magenta highlights."));
5488 gtk_widget_set_tooltip_text(
g->noise_level, _(
"add statistical noise in reconstructed highlights.\n"
5489 "this avoids highlights to look too smooth\n"
5490 "when the picture is noisy overall,\n"
5491 "so they blend with the rest of the picture."));
5495 gtk_widget_set_tooltip_text(
g->noise_distribution, _(
"choose the statistical distribution of noise.\n"
5496 "this is useful to match natural sensor noise pattern.\n"));
5507 gtk_widget_set_tooltip_text(
g->contrast, _(
"slope of the linear part of the curve\n"
5508 "affects mostly the mid-tones"));
5512 gtk_widget_set_tooltip_text(
g->output_power, _(
"equivalent to paper grade in analog.\n"
5513 "increase to make highlights brighter and less compressed.\n"
5514 "decrease to mute highlights."));
5524 gtk_widget_set_tooltip_text(
g->toe,
5525 _(
"distance between middle gray and the start of the shadows roll-off.\n"
5526 "0% keeps the toe at middle gray, 100% pushes it to the point where the\n"
5527 "current slope would hit the output black level."));
5535 gtk_widget_set_tooltip_text(
g->shoulder,
5536 _(
"distance between middle gray and the start of the highlights roll-off.\n"
5537 "0% keeps the shoulder at middle gray, 100% pushes it to the point where the\n"
5538 "current slope would hit the output white level."));
5543 gtk_widget_set_tooltip_text(
g->highlights, _(
"shape of the highlights roll-off of the curve.\n"
5544 "perceptual (default) is a generalized sigmoid derived from a\n"
5545 "perceptual appearance model: always smooth and monotonic.\n"
5546 "hard/soft/safe are the legacy polynomial/rational segments;\n"
5547 "hard compresses highlights more, soft less."));
5550 gtk_widget_set_tooltip_text(
g->shadows, _(
"shape of the shadows roll-off of the curve.\n"
5551 "perceptual (default) is a generalized sigmoid derived from a\n"
5552 "perceptual appearance model: always smooth and monotonic.\n"
5553 "hard/soft/safe are the legacy polynomial/rational segments;\n"
5554 "hard compresses shadows more, soft less."));
5562 gtk_widget_set_tooltip_text(
g->saturation, _(
"desaturates the output of the module\n"
5563 "specifically at extreme luminances.\n"
5564 "increase if shadows and/or highlights are under-saturated."));
5567 gtk_widget_set_tooltip_text(
g->preserve_color, _(
"ensure the original color are preserved.\n"
5568 "may reinforce chromatic aberrations and chroma noise,\n"
5569 "so ensure they are properly corrected elsewhere.\n"));
5576 gtk_widget_set_tooltip_text(
g->version,
5577 _(
"v3 is darktable 3.0 desaturation method, same as color balance.\n"
5578 "v4 is a newer desaturation method, based on spectral purity of light.\n"
5579 "v8 tone maps each RGB channel separately in an inset rendering space:\n"
5580 "highlights bleach toward white and hues drift as tonal compression\n"
5581 "increases, with a parametric hue recovery on the saturation slider."));
5586 gtk_widget_set_tooltip_text(
g->spline_version,
5587 _(
"how the latitude, balance and contrast place the toe and\n"
5588 "shoulder nodes of the curve (not the shape between them —\n"
5589 "that is 'contrast in shadows/highlights').\n"
5590 "v3 (2021) is recommended; v1/v2 are kept for older edits."));
5594 gtk_widget_set_tooltip_text(
5595 g->auto_hardness, _(
"enable to auto-set the look hardness depending on the scene white and black points.\n"
5596 "this keeps the middle gray on the identity line and improves fast tuning.\n"
5597 "disable if you want a manual control."));
5606 gtk_widget_set_tooltip_text(
g->black_point_target, _(
"luminance of output pure black, "
5607 "this should be 0%\nexcept if you want a faded look"));
5612 gtk_widget_set_tooltip_text(
g->grey_point_target,
5613 _(
"middle gray value of the target display or color space.\n"
5614 "you should never touch that unless you know what you are doing."));
5620 gtk_widget_set_tooltip_text(
g->white_point_target, _(
"luminance of output pure white, "
5621 "this should be 100%\nexcept if you want a faded look"));
5626 gtk_box_pack_start(GTK_BOX(self->
widget),
5628 "plugins/darkroom/filmicrgb/graphheight", 230, 100),
5630 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
g->notebook),
FALSE,
FALSE, 0);
5638 if(
IS_NULL_PTR(w) || w ==
g->auto_hardness || w ==
g->security_factor || w ==
g->grey_point_source
5639 || w ==
g->black_point_source || w ==
g->white_point_source)
5643 if(w ==
g->security_factor || w ==
g->grey_point_source)
5645 float prev = *(
float *)previous;
5646 if(w ==
g->security_factor)
5648 float ratio = (
p->security_factor - prev) / (prev + 100.0f);
5650 float EVmin =
p->black_point_source;
5651 EVmin = EVmin + ratio * EVmin;
5653 float EVmax =
p->white_point_source;
5654 EVmax = EVmax + ratio * EVmax;
5656 p->white_point_source = EVmax;
5657 p->black_point_source = EVmin;
5661 float grey_var = log2f(prev /
p->grey_point_source);
5662 p->black_point_source =
p->black_point_source - grey_var;
5663 p->white_point_source =
p->white_point_source + grey_var;
5670 if(
p->auto_hardness)
5671 p->output_power = logf(
p->grey_point_target / 100.0f)
5672 / logf(-
p->black_point_source / (
p->white_point_source -
p->black_point_source));
5674 gtk_widget_set_visible(GTK_WIDGET(
g->output_power), !
p->auto_hardness);
5685 gtk_widget_set_tooltip_text(
g->saturation, _(
"how much of the per-channel hue drift to keep.\n"
5686 "saturation is not affected: valid diffuse colors\n"
5687 "(skin tones, product colors) keep their saturation and\n"
5688 "strongly compressed colors bleach, at any setting.\n"
5689 "-100%% is pure AgX: full hue drift (the 'film' look).\n"
5690 "0%% (default) removes half the hue drift.\n"
5691 "+100%% restores the original hues exactly."));
5692 gtk_widget_set_visible(GTK_WIDGET(
g->preserve_color),
FALSE);
5697 gtk_widget_set_tooltip_text(
g->saturation, _(
"desaturates the output of the module\n"
5698 "specifically at extreme luminances.\n"
5699 "increase if shadows and/or highlights are under-saturated."));
5704 gtk_widget_set_tooltip_text(
g->saturation, _(
"desaturates the output of the module\n"
5705 "specifically at medium luminances.\n"
5706 "increase if midtones are under-saturated."));
5711 gtk_widget_set_tooltip_text(
g->saturation, _(
"Positive values ensure saturation is kept unchanged over the whole range.\n"
5712 "Negative values bleache highlights at constant hue and luminance.\n"
5713 "Zero is an equal mix of both strategies."));
5714 gtk_widget_set_visible(GTK_WIDGET(
g->preserve_color),
FALSE);
5719 gtk_widget_set_visible(GTK_WIDGET(
g->preserve_color),
TRUE);
5722 if(
IS_NULL_PTR(w) || w ==
g->reconstruct_bloom_vs_details)
5724 if(
p->reconstruct_bloom_vs_details == -100.f)
5729 gtk_widget_set_sensitive(
g->reconstruct_structure_vs_texture,
FALSE);
5733 gtk_widget_set_sensitive(
g->reconstruct_structure_vs_texture,
TRUE);
5739 gtk_widget_set_visible(
g->grey_point_source,
p->custom_grey);
5740 gtk_widget_set_visible(
g->grey_point_target,
p->custom_grey);
5744 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
static void error(char *msg)
void dt_bauhaus_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
float dt_bauhaus_slider_get(GtkWidget *widget)
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
void dt_bauhaus_slider_set(GtkWidget *widget, float 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)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
static void set_color(cairo_t *cr, GdkRGBA color)
static __DT_CLONE_TARGETS__ void normalize(float *const buffer, const size_t width, const size_t height, const float norm)
static void blur_2D_Bspline(const float *const restrict in, float *const restrict out, float *const restrict tempbuf, const size_t width, const size_t height, const int mult, const gboolean clip_negatives)
const dt_colormatrix_t XYZ_D65_to_D50_CAT16
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
static float dt_camera_rgb_luminance(const float4 rgb)
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
static float4 LMS_to_XYZ(const float4 LMS)
static float4 Yrg_to_LMS(const float4 Yrg)
static float4 LMS_to_Yrg(const float4 LMS)
static float4 XYZ_to_LMS(const float4 XYZ)
dt_colorspaces_color_profile_type_t
dt_colorspaces_color_mode_t
static dt_aligned_pixel_t rgb
static const float const float const float min
static dt_aligned_pixel_t XYZ
const dt_colormatrix_t dt_aligned_pixel_t out
dt_store_simd_aligned(out, dt_mat3x4_mul_vec4(vin, dt_colormatrix_row_to_simd(matrix, 0), dt_colormatrix_row_to_simd(matrix, 1), dt_colormatrix_row_to_simd(matrix, 2)))
static const dt_colormatrix_t M
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
dt_image_pipe_class_t dt_image_pipe_class(const dt_image_t *img)
const char * dt_image_pipe_class_name(const dt_image_pipe_class_t klass)
float dt_image_get_exposure_bias(const struct dt_image_t *image_storage)
gboolean dt_image_needs_rawprepare(const dt_image_t *img)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
#define __OMP_SIMD__(...)
#define dt_gui_freeze_begin()
#define dt_gui_freeze_end()
#define for_each_channel(_var,...)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
void void void gboolean dt_gui_widgets_suppressed(void)
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define __OMP_DECLARE_SIMD__(...)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
static const dt_aligned_pixel_simd_t value
#define __OMP_PARALLEL_FOR_SIMD__(...)
#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 float4 dt_noise_generator_simd(const dt_noise_distribution_t distribution, const float4 mu, const float4 param, uint state[4])
static unsigned int splitmix32(const unsigned long seed)
static float xoshiro128plus(uint state[4])
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_update_history_main(dev)
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
@ DT_DEV_PIXELPIPE_DISPLAY_PASSTHRU
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
static float dt_log_scale_axis(const float x, const float base)
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_loglog_grid(cairo_t *cr, const int num, const int left, const int top, const int right, const int bottom, const float base)
void dtgtk_cairo_paint_refresh(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_showmask(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_text_label(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void(* DTGTKCairoPaintIconFunc)(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
static void toe_shoulder_callback(GtkWidget *slider, gpointer user_data)
static gboolean area_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static void _filmic_agx_Yrg_to_xyz_D50(const dt_aligned_pixel_t Yrg, dt_aligned_pixel_t xyz_D50)
static gboolean area_scroll_callback(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
const char ** description(struct dt_iop_module_t *self)
static gboolean area_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
static gboolean _filmic_agx_build_displaced(const dt_iop_order_iccprofile_info_t *const work_profile, const float inset[3], const float rotation[3], dt_colormatrix_t M)
static __DT_CLONE_TARGETS__ void display_mask(const float *const restrict mask, float *const restrict out, const size_t width, const size_t height)
dt_iop_filmic_noise_distribution_t
@ DT_FILMIC_NOISE_UNIFORM
@ DT_FILMIC_NOISE_POISSONIAN
@ DT_FILMIC_NOISE_GAUSSIAN
dt_iop_filmicrgb_curve_type_t
@ DT_FILMIC_CURVE_RATIONAL
@ DT_FILMIC_CURVE_SIGMOID
void gui_reset(dt_iop_module_t *self)
void filmic_gui_draw_icon(cairo_t *cr, struct dt_iop_filmicrgb_gui_button_data_t *button, struct dt_iop_filmicrgb_gui_data_t *g)
static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
dt_iop_filmic_rgb_gui_mode_t
@ DT_FILMIC_GUI_BASECURVE
@ DT_FILMIC_GUI_BASECURVE_LOG
static __DT_CLONE_TARGETS__ void filmic_split_v1(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const size_t width, const size_t height)
void reload_defaults(dt_iop_module_t *module)
static __DT_CLONE_TARGETS__ void wavelets_reconstruct_RGB(const float *const restrict HF, const float *const restrict LF, const float *const restrict texture, const float *const restrict mask, float *const restrict reconstructed, const size_t width, const size_t height, const size_t ch, const float gamma, const float gamma_comp, const float beta, const float beta_comp, const float delta, const size_t s, const size_t scales)
static void _filmic_agx_xyz_D50_to_Yrg(const dt_aligned_pixel_t xyz_D50, dt_aligned_pixel_t Yrg)
dt_iop_filmicrgb_colorscience_type_t
@ DT_FILMIC_COLORSCIENCE_V1
@ DT_FILMIC_COLORSCIENCE_V2
@ DT_FILMIC_COLORSCIENCE_V7
@ DT_FILMIC_COLORSCIENCE_V9
@ DT_FILMIC_COLORSCIENCE_V5
@ DT_FILMIC_COLORSCIENCE_V4
@ DT_FILMIC_COLORSCIENCE_V6
@ DT_FILMIC_COLORSCIENCE_V3
@ DT_FILMIC_COLORSCIENCE_V10
@ DT_FILMIC_COLORSCIENCE_V8
__DT_CLONE_TARGETS__ int process(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const restrict ivoid, void *const restrict ovoid)
void gui_update(dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
static void dt_cairo_draw_arrow(cairo_t *cr, double origin_x, double origin_y, double destination_x, double destination_y, gboolean show_head)
static void apply_auto_grey(dt_iop_module_t *self, const dt_iop_order_iccprofile_info_t *const work_profile)
static __DT_CLONE_TARGETS__ void filmic_chroma_v2_v3(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const int variant, const size_t width, const size_t height, const size_t ch, const dt_iop_filmicrgb_colorscience_type_t colorscience_version)
static void apply_auto_black(dt_iop_module_t *self, const dt_iop_order_iccprofile_info_t *const work_profile)
static __DT_CLONE_TARGETS__ void wavelets_reconstruct_ratios(const float *const restrict HF, const float *const restrict LF, const float *const restrict texture, const float *const restrict mask, float *const restrict reconstructed, const size_t width, const size_t height, const size_t ch, const float gamma, const float gamma_comp, const float beta, const float beta_comp, const float delta, const size_t s, const size_t scales)
static void _mat3_identity(dt_colormatrix_t M)
void gui_focus(struct dt_iop_module_t *self, gboolean in)
static cl_int reconstruct_highlights_cl(const dt_dev_pixelpipe_t *pipe, cl_mem in, cl_mem mask, cl_mem reconstructed, const dt_iop_filmicrgb_reconstruction_type_t variant, dt_iop_filmicrgb_global_data_t *const gd, const dt_iop_filmicrgb_data_t *const data, const dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *const roi_in)
#define CIE_Y_1931_to_CIE_Y_2006(x)
static __DT_CLONE_TARGETS__ void filmic_chroma_v4(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_order_iccprofile_info_t *const export_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const int variant, const size_t width, const size_t height, const size_t ch, const dt_iop_filmicrgb_colorscience_type_t colorscience_version, const float display_black, const float display_white)
static __DT_CLONE_TARGETS__ void filmic_chroma_v1(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const int variant, const size_t width, const size_t height)
static __DT_CLONE_TARGETS__ void filmic_split_v4(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_order_iccprofile_info_t *const export_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const int variant, const size_t width, const size_t height, const size_t ch, const dt_iop_filmicrgb_colorscience_type_t colorscience_version, const float display_black, const float display_white)
void gui_init(dt_iop_module_t *self)
dt_iop_filmicrgb_methods_type_t
@ DT_FILMIC_METHOD_POWER_NORM
@ DT_FILMIC_METHOD_EUCLIDEAN_NORM_V1
@ DT_FILMIC_METHOD_MAX_RGB
@ DT_FILMIC_METHOD_EUCLIDEAN_NORM_V2
@ DT_FILMIC_METHOD_LUMINANCE
static __DT_CLONE_TARGETS__ void filmic_split_v2_v3(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const size_t width, const size_t height)
static float log_tonemapping(const float x, const float grey, const float black, const float dynamic_range)
dt_iop_filmicrgb_reconstruction_type_t
@ DT_FILMIC_RECONSTRUCT_RATIOS
@ DT_FILMIC_RECONSTRUCT_RGB
static void filmic_v3_legacy_to_direct(const dt_iop_filmicrgb_params_t *const p, float *const toe, float *const shoulder)
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
dt_iop_filmicrgb_gui_button_t
@ DT_FILMIC_GUI_BUTTON_LAST
@ DT_FILMIC_GUI_BUTTON_LABELS
@ DT_FILMIC_GUI_BUTTON_TYPE
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
static __DT_CLONE_TARGETS__ int get_scales(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *roi_in, const dt_dev_pixelpipe_iop_t *const piece)
static int reconstruct_highlights(const dt_dev_pixelpipe_t *const pipe, const float *const restrict in, const float *const restrict mask, float *const restrict reconstructed, const dt_iop_filmicrgb_reconstruction_type_t variant, const size_t ch, const dt_iop_filmicrgb_data_t *const data, const dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
void commit_params(dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void apply_auto_white_point_source(dt_iop_module_t *self, const dt_iop_order_iccprofile_info_t *const work_profile)
static float exp_tonemapping_v2(const float x, const float grey, const float black, const float dynamic_range)
void cleanup_global(dt_iop_module_so_t *module)
static void filmic_prepare_simd_matrices(const dt_colormatrix_t input_matrix, const dt_colormatrix_t output_matrix, const dt_colormatrix_t export_input_matrix, const dt_colormatrix_t export_output_matrix, dt_iop_filmicrgb_simd_matrices_t *const simd_matrices)
static gboolean area_enter_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
void cleanup_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static __DT_CLONE_TARGETS__ gint mask_clipped_pixels(const float *const restrict in, float *const restrict mask, const float normalize, const float feathering, const size_t width, const size_t height, const size_t ch)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
static gboolean area_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
static void inpaint_noise(const float *const in, const float *const mask, float *const inpainted, const float noise_level, const float threshold, const dt_noise_distribution_t noise_distribution, const size_t width, const size_t height)
static void apply_autotune(dt_iop_module_t *self, const dt_iop_order_iccprofile_info_t *const work_profile)
static __DT_CLONE_TARGETS__ void filmic_agx(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_order_iccprofile_info_t *const export_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const size_t width, const size_t height, const size_t ch, const float display_black, const float display_white)
static __DT_CLONE_TARGETS__ void filmic_v5(const float *const restrict in, float *const restrict out, const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_order_iccprofile_info_t *const export_profile, const dt_iop_filmicrgb_data_t *const data, const dt_iop_filmic_rgb_spline_t spline, const size_t width, const size_t height, const size_t ch, const float display_black, const float display_white)
static gboolean filmic_v3_compute_geometry(const dt_iop_filmicrgb_params_t *const p, dt_iop_filmicrgb_v3_geometry_t *const geometry)
static void show_mask_callback(GtkToggleButton *button, GdkEventButton *event, gpointer user_data)
static const dt_iop_order_iccprofile_info_t * _filmic_get_output_profile(const dt_dev_pixelpipe_t *pipe)
static __DT_CLONE_TARGETS__ void wavelets_detail_level(const float *const restrict detail, const float *const restrict LF, float *const restrict HF, float *const restrict texture, const size_t width, const size_t height, const size_t ch)
static void convert_to_spline_v3(dt_iop_filmicrgb_params_t *n)
static __DT_CLONE_TARGETS__ void compute_ratios(const float *const restrict in, float *const restrict norms, float *const restrict ratios, const dt_iop_order_iccprofile_info_t *const work_profile, const int variant, const size_t width, const size_t height)
static void filmic_v3_direct_to_legacy(const dt_iop_filmicrgb_params_t *const p, const float toe, const float shoulder, float *const latitude, float *const balance)
dt_iop_filmicrgb_spline_version_type_t
@ DT_FILMIC_SPLINE_VERSION_V2
@ DT_FILMIC_SPLINE_VERSION_V3
@ DT_FILMIC_SPLINE_VERSION_V1
static float filmic_sigmoid_scale(const float limit_x, const float limit_y, const float transition_x, const float transition_y, const float slope, const float power)
void init_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void filmic_gui_sync_toe_shoulder(dt_iop_module_t *self)
void init_global(dt_iop_module_so_t *module)
void autoset(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *i)
static void filmic_agx_prepare_bracket(const dt_iop_order_iccprofile_info_t *const work_profile, const dt_iop_filmicrgb_colorscience_type_t variant, dt_colormatrix_t inset, dt_colormatrix_t outset)
static gboolean filmic_v3_compute_nodes_from_legacy(const dt_iop_filmicrgb_params_t *const p, dt_iop_filmicrgb_v3_geometry_t *const geometry, dt_iop_filmicrgb_v3_nodes_t *const nodes)
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
static gboolean _filmic_is_agx(const dt_iop_filmicrgb_colorscience_type_t v)
static __DT_CLONE_TARGETS__ void init_reconstruct(const float *const restrict in, const float *const restrict mask, float *const restrict reconstructed, const size_t width, const size_t height)
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static float linear_saturation(const float x, const float luminance, const float saturation)
static gboolean dt_iop_filmic_rgb_compute_spline(const dt_iop_filmicrgb_params_t *const p, struct dt_iop_filmic_rgb_spline_t *const spline)
static __DT_CLONE_TARGETS__ void restore_ratios(float *const restrict ratios, const float *const restrict norms, const size_t width, const size_t height)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
gboolean runtime_data_hash(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
static int gauss_solve(double *A, double *b, int n)
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()
void dt_gui_set_pango_resolution(PangoLayout *layout)
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
void dt_ui_notebook_set_picker_owner(GtkNotebook *notebook, gpointer owner)
Register an opaque owner for a GtkNotebook's page switches, and relay every "switch_page" as DT_SIGNA...
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
static GtkWidget * dt_ui_section_label_new(const gchar *str)
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
static GtkWidget * dt_ui_label_new(const gchar *str)
void dt_iop_request_focus(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)
float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
#define dt_omploop_sfence()
#define dt_iop_fmt_log(module, fmt,...)
Debug helper to trace a module's input-format-driven decisions on the -d pipe channel (DT_DEBUG_PIPE)...
@ IOP_FLAGS_INCLUDE_IN_STYLES
@ IOP_FLAGS_SUPPORTS_BLENDING
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_iop_togglebutton_new(dt_iop_module_t *self, const char *section, const gchar *label, const gchar *ctrl_label, GCallback callback, gboolean local, guint accel_key, GdkModifierType mods, DTGTKCairoPaintIconFunc paint, GtkWidget *box)
GtkWidget * dt_bauhaus_toggle_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_output_profile_info(const struct dt_dev_pixelpipe_t *pipe)
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)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_work_profile_info(const struct dt_dev_pixelpipe_t *pipe)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_current_profile_info(dt_iop_module_t *module, const struct dt_dev_pixelpipe_t *pipe)
void dt_ioppr_free_iccprofile_params_cl(dt_colorspaces_iccprofile_info_cl_t **_profile_info_cl, cl_float **_profile_lut_cl, cl_mem *_dev_profile_info, cl_mem *_dev_profile_lut)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_iop_work_profile_info(struct dt_iop_module_t *module, GList *iop_list)
cl_int dt_ioppr_build_iccprofile_params_cl(const dt_iop_order_iccprofile_info_t *const profile_info, const int devid, dt_colorspaces_iccprofile_info_cl_t **_profile_info_cl, cl_float **_profile_lut_cl, cl_mem *_dev_profile_info, cl_mem *_dev_profile_lut)
const float *const const float coeff[3]
float *const restrict luminance
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define CLAMPF(a, mn, mx)
float DT_ALIGNED_ARRAY dt_colormatrix_t[4][4]
static void transpose_3xSSE(const dt_colormatrix_t input, dt_colormatrix_t output)
static void pack_3xSSE_to_3x4(const dt_colormatrix_t input, float output[12])
static void dt_colormatrix_mul(dt_colormatrix_t dst, const dt_colormatrix_t m1, const dt_colormatrix_t m2)
static int mat3SSEinv(dt_colormatrix_t dst, const dt_colormatrix_t src)
float dt_aligned_pixel_t[4]
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
void * dt_opencl_alloc_device_buffer(const int devid, const size_t size)
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
int dt_opencl_create_kernel(const int prog, const char *name)
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
int dt_opencl_write_buffer_to_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
int dt_opencl_read_buffer_from_device(const int devid, void *host, void *device, const size_t offset, const size_t size, const int blocking)
void dt_opencl_free_kernel(const int kernel)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes, const size_t *local)
void dt_opencl_release_mem_object(cl_mem mem)
static float fmaxabsf(const float a, const float b)
static float clamp_simd(const float x)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
const float const int flip
int32_t num_openmp_threads
struct dt_gui_gtk_t * gui
struct dt_colorspaces_t * color_profiles
struct dt_bauhaus_t * bauhaus
struct dt_develop_t * develop
PangoFontDescription * pango_font_desc
dt_colorspaces_color_profile_type_t softproof_type
dt_colorspaces_color_mode_t mode
char softproof_filename[512]
dt_iop_color_intent_t softproof_intent
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
struct dt_develop_t * dev
dt_iop_buffer_type_t datatype
dt_iop_filmicrgb_curve_type_t type[2]
int high_quality_reconstruction
float reconstruct_feather
char softproof_filename[512]
float reconstruct_structure_vs_texture
float reconstruct_grey_vs_color
dt_noise_distribution_t noise_distribution
dt_colorspaces_color_profile_type_t softproof_type
float reconstruct_bloom_vs_details
dt_colorspaces_color_mode_t softproof_mode
struct dt_iop_filmic_rgb_spline_t spline DT_ALIGNED_ARRAY
float reconstruct_threshold
int kernel_filmic_rgb_chroma
int kernel_filmic_bspline_vertical
int kernel_filmic_rgb_split
int kernel_filmic_wavelets_reconstruct
int kernel_filmic_wavelets_detail
int kernel_filmic_show_mask
int kernel_filmic_compute_ratios
int kernel_filmic_init_reconstruct
int kernel_filmic_restore_ratios
int kernel_filmic_bspline_vertical_local
int kernel_filmic_bspline_horizontal
int kernel_filmic_inpaint_noise
int kernel_filmic_bspline_horizontal_local
GtkWidget * high_quality_reconstruction
GtkWidget * autoset_display_gamma
GtkWidget * reconstruct_grey_vs_color
GtkWidget * auto_hardness
dt_iop_filmicrgb_gui_button_data_t buttons[DT_FILMIC_GUI_BUTTON_LAST]
GtkWidget * reconstruct_bloom_vs_details
GtkWidget * reconstruct_threshold
GtkWidget * show_highlight_mask
GtkWidget * white_point_target
GtkWidget * grey_point_source
GtkWidget * spline_version
GtkStyleContext * context
GtkWidget * preserve_color
dt_iop_filmicrgb_gui_button_t active_button
GtkWidget * grey_point_target
dt_iop_filmic_rgb_gui_mode_t gui_mode
GtkWidget * black_point_source
GtkWidget * reconstruct_structure_vs_texture
GtkWidget * reconstruct_feather
GtkWidget * noise_distribution
GtkWidget * black_point_target
struct dt_iop_filmic_rgb_spline_t spline DT_ALIGNED_ARRAY
GtkWidget * white_point_source
GtkWidget * security_factor
GtkWidget * compensate_icc_black
float reconstruct_threshold
float reconstruct_grey_vs_color
float reconstruct_feather
dt_iop_filmicrgb_curve_type_t shadows
dt_iop_filmicrgb_spline_version_type_t spline_version
dt_iop_filmicrgb_colorscience_type_t version
dt_iop_filmic_noise_distribution_t noise_distribution
dt_iop_filmicrgb_methods_type_t preserve_color
int high_quality_reconstruction
dt_iop_filmicrgb_curve_type_t highlights
float reconstruct_bloom_vs_details
gboolean compensate_icc_black
float reconstruct_structure_vs_texture
dt_aligned_pixel_simd_t input[3]
dt_aligned_pixel_simd_t output[3]
dt_aligned_pixel_simd_t export_output[3]
dt_aligned_pixel_simd_t export_input[3]
gboolean contrast_clamped
dt_iop_global_data_t * data
GtkDarktableToggleButton * off
dt_iop_params_t * default_params
struct dt_develop_t * dev
dt_iop_gui_data_t * gui_data
dt_iop_global_data_t * global_data
gboolean workflow_enabled
dt_aligned_pixel_t picked_color_min
dt_aligned_pixel_t picked_color_max
dt_aligned_pixel_t picked_color
dt_colormatrix_t matrix_out
dt_colormatrix_t matrix_in_transposed
dt_colormatrix_t matrix_in
Region of interest passed through the pixelpipe.