76#define ANGLE_SHIFT -30.f
77#define DEG_TO_RAD(x) ((x + ANGLE_SHIFT) * M_PI / 180.f)
78#define RAD_TO_DEG(x) (x * 180.f / M_PI - ANGLE_SHIFT)
214 return _(
"color _balance");
219 return _(
"offset power slope|cdl|color grading|contrast|chroma_highlights|hue|vibrance|saturation");
225 _(
"corrective or creative"),
226 _(
"linear, RGB, scene-referred"),
227 _(
"non-linear, RGB"),
228 _(
"non-linear, RGB, scene-referred"));
255 const int new_version)
257 if(old_version == 1 && new_version == 5)
259 typedef struct dt_iop_colorbalancergb_params_v1_t
273 float shadows_weight;
275 float highlights_weight;
276 float chroma_shadows;
277 float chroma_highlights;
279 float chroma_midtones;
280 float saturation_global;
281 float saturation_highlights;
282 float saturation_midtones;
283 float saturation_shadows;
285 } dt_iop_colorbalancergb_params_v1_t;
291 memcpy(new_params, old_params,
sizeof(dt_iop_colorbalancergb_params_v1_t));
295 n->mask_grey_fulcrum = 0.1845f;
297 n->grey_fulcrum = 0.1845f;
304 if(old_version == 2 && new_version == 5)
306 typedef struct dt_iop_colorbalancergb_params_v2_t
321 float shadows_weight;
323 float highlights_weight;
324 float chroma_shadows;
325 float chroma_highlights;
327 float chroma_midtones;
328 float saturation_global;
329 float saturation_highlights;
330 float saturation_midtones;
331 float saturation_shadows;
335 float brilliance_global;
336 float brilliance_highlights;
337 float brilliance_midtones;
338 float brilliance_shadows;
340 } dt_iop_colorbalancergb_params_v2_t;
346 memcpy(new_params, old_params,
sizeof(dt_iop_colorbalancergb_params_v2_t));
351 n->grey_fulcrum = 0.1845f;
357 if(old_version == 3 && new_version == 5)
359 typedef struct dt_iop_colorbalancergb_params_v3_t
374 float shadows_weight;
376 float highlights_weight;
377 float chroma_shadows;
378 float chroma_highlights;
380 float chroma_midtones;
381 float saturation_global;
382 float saturation_highlights;
383 float saturation_midtones;
384 float saturation_shadows;
388 float brilliance_global;
389 float brilliance_highlights;
390 float brilliance_midtones;
391 float brilliance_shadows;
394 float mask_grey_fulcrum;
396 } dt_iop_colorbalancergb_params_v3_t;
402 memcpy(new_params, old_params,
sizeof(dt_iop_colorbalancergb_params_v3_t));
406 n->grey_fulcrum = 0.1845f;
412 if(old_version == 4 && new_version == 5)
414 typedef struct dt_iop_colorbalancergb_params_v4_t
429 float shadows_weight;
431 float highlights_weight;
432 float chroma_shadows;
433 float chroma_highlights;
435 float chroma_midtones;
436 float saturation_global;
437 float saturation_highlights;
438 float saturation_midtones;
439 float saturation_shadows;
443 float brilliance_global;
444 float brilliance_highlights;
445 float brilliance_midtones;
446 float brilliance_shadows;
449 float mask_grey_fulcrum;
456 } dt_iop_colorbalancergb_params_v4_t;
462 memcpy(new_params, old_params,
sizeof(dt_iop_colorbalancergb_params_v4_t));
480 p.highlights_weight = 1.f;
481 p.mask_grey_fulcrum = 0.1845f;
482 p.grey_fulcrum = 0.1845f;
483 p.white_fulcrum = 1.f;
487 p.chroma_global = 0.2f;
488 p.saturation_shadows = 0.1f;
489 p.saturation_midtones = 0.05f;
490 p.saturation_highlights = -0.05f;
495 p.chroma_global = 0.f;
497 p.saturation_global = 0.2f;
498 p.saturation_shadows = 0.30f;
499 p.saturation_midtones = 0.f;
500 p.saturation_highlights = 0.f;
503 p.saturation_global = 0.2f;
504 p.saturation_shadows = 0.5f;
505 p.saturation_midtones = 0.f;
506 p.saturation_highlights = 0.0f;
509 p.saturation_global = 0.2f;
510 p.saturation_shadows = 0.25f;
511 p.saturation_midtones = 0.f;
512 p.saturation_highlights = 0.0f;
521__OMP_DECLARE_SIMD__(aligned(output, output_comp: 16) uniform(shadows_weight, midtones_weight, highlights_weight))
522static inline
void opacity_masks(const float
x,
523 const float shadows_weight, const float highlights_weight,
524 const float midtones_weight, const float mask_grey_fulcrum,
527 const float x_offset = (
x - mask_grey_fulcrum);
528 const float x_offset_norm = x_offset / mask_grey_fulcrum;
529 const float alpha = 1.f / (1.f + expf(x_offset_norm * shadows_weight));
530 const float beta = 1.f / (1.f + expf(-x_offset_norm * highlights_weight));
531 const float alpha_comp = 1.f - alpha;
532 const float beta_comp = 1.f - beta;
533 const float gamma = expf(-sqf(x_offset) * midtones_weight / 4.f) * sqf(alpha_comp) * sqf(beta_comp) * 8.f;
534 const float gamma_comp = 1.f - gamma;
543 output_comp[0] = alpha_comp;
544 output_comp[1] = gamma_comp;
545 output_comp[2] = beta_comp;
546 output_comp[3] = 0.f;
550static inline float soft_clip(
const float x,
const float soft_threshold,
const float hard_threshold)
554 const float norm = hard_threshold - soft_threshold;
555 return (
x > soft_threshold) ? soft_threshold + (1.f - expf(-(
x - soft_threshold) / norm)) * norm :
x;
559static inline float lookup_gamut(
const float *
const gamut_lut,
const float x)
567 float x_prev = floorf(x_test);
568 float x_next = ceilf(x_test);
572 int xi = (int)x_prev;
576 int xii = (int)x_next;
578 else if(xii >
LUT_ELEM - 1) xii = 0;
581 const float y_prev = gamut_lut[xi];
582 const float y_next = gamut_lut[xii];
590 out += (x_test - x_prev) * (y_next - y_prev) / (x_next - x_prev);
644 const float *
const restrict in = __builtin_assume_aligned(((
const float *
const restrict)ivoid), 64);
645 float *
const restrict
out = __builtin_assume_aligned(((
float *
const restrict)
ovoid), 64);
646 const float *
const restrict gamut_LUT = __builtin_assume_aligned(((
const float *
const restrict)
d->gamut_LUT), 64);
648 const float *
const restrict global = __builtin_assume_aligned((
const float *
const restrict)
d->global, 16);
649 const float *
const restrict highlights = __builtin_assume_aligned((
const float *
const restrict)
d->highlights, 16);
650 const float *
const restrict shadows = __builtin_assume_aligned((
const float *
const restrict)
d->shadows, 16);
651 const float *
const restrict midtones = __builtin_assume_aligned((
const float *
const restrict)
d->midtones, 16);
653 const float *
const restrict chroma = __builtin_assume_aligned((
const float *
const restrict)
d->chroma, 16);
654 const float *
const restrict saturation = __builtin_assume_aligned((
const float *
const restrict)
d->saturation, 16);
655 const float *
const restrict brilliance = __builtin_assume_aligned((
const float *
const restrict)
d->brilliance, 16);
657 const dt_aligned_pixel_simd_t input0 = dt_colormatrix_row_to_simd(input_matrix_transposed, 0);
658 const dt_aligned_pixel_simd_t input1 = dt_colormatrix_row_to_simd(input_matrix_transposed, 1);
659 const dt_aligned_pixel_simd_t input2 = dt_colormatrix_row_to_simd(input_matrix_transposed, 2);
660 const dt_aligned_pixel_simd_t output0 = dt_colormatrix_row_to_simd(output_matrix_transposed, 0);
661 const dt_aligned_pixel_simd_t output1 = dt_colormatrix_row_to_simd(output_matrix_transposed, 1);
662 const dt_aligned_pixel_simd_t output2 = dt_colormatrix_row_to_simd(output_matrix_transposed, 2);
664 const dt_aligned_pixel_simd_t global_v = dt_load_simd_aligned(global);
665 const dt_aligned_pixel_simd_t highlights_v = dt_load_simd_aligned(highlights);
666 const dt_aligned_pixel_simd_t shadows_v = dt_load_simd_aligned(shadows);
667 const dt_aligned_pixel_simd_t midtones_v = dt_load_simd_aligned(midtones);
668 const dt_aligned_pixel_simd_t jz_ai0 = dt_colormatrix_row_to_simd(AI_transposed, 0);
669 const dt_aligned_pixel_simd_t jz_ai1 = dt_colormatrix_row_to_simd(AI_transposed, 1);
670 const dt_aligned_pixel_simd_t jz_ai2 = dt_colormatrix_row_to_simd(AI_transposed, 2);
672 const gboolean mask_display =
d->mask_display;
674 const dt_aligned_pixel_simd_t checker_color_1_v = dt_load_simd(
d->checker_color_1);
675 const dt_aligned_pixel_simd_t checker_color_2_v = dt_load_simd(
d->checker_color_2);
676 const size_t checker_1
678 const size_t checker_2 = 2 * checker_1;
679 const size_t npixels = (size_t)roi_out->
width * roi_out->
height;
680 const size_t out_width = roi_out->
width;
684 { cosf(
d->hue_angle), -sinf(
d->hue_angle) },
685 { sinf(
d->hue_angle), cosf(
d->hue_angle) },
688 for(
size_t idx = 0; idx < npixels; idx++)
690 const size_t k = idx * 4;
691 const float *
const restrict pix_in = __builtin_assume_aligned(in +
k, 16);
692 float *
const restrict pix_out = __builtin_assume_aligned(
out +
k, 16);
693 const dt_aligned_pixel_simd_t pix_in_v = dt_load_simd_aligned(pix_in);
695 dt_aligned_pixel_simd_t RGB_v = dt_simd_max_zero(pix_in_v);
697 const dt_aligned_pixel_simd_t LMS_v = dt_mat3x4_mul_vec4(RGB_v, input0, input1, input2);
698 dt_aligned_pixel_simd_t Yrg_v = LMS_to_Yrg_simd(LMS_v);
699 Yrg_v[0] =
MAX(Yrg_v[0], 0.f);
702 opacity_masks(powf(Yrg_v[0], 0.4101205819200422f),
d->shadows_weight,
d->highlights_weight,
703 d->midtones_weight,
d->mask_grey_fulcrum, opacities, opacities_comp);
707 const float r_centered = Yrg_v[1] - 0.21902143f;
708 const float g_centered = Yrg_v[2] - 0.54371398f;
709 const float r_rotated = hue_rotation_matrix[0][0] * r_centered + hue_rotation_matrix[0][1] * g_centered;
710 const float g_rotated = hue_rotation_matrix[1][0] * r_centered + hue_rotation_matrix[1][1] * g_centered;
711 const float chroma_in = dt_fast_hypotf(g_rotated, r_rotated);
712 const float inv_chroma_in = (chroma_in > 0.f) ? 1.f / chroma_in : 0.f;
713 const float cos_h = r_rotated * inv_chroma_in;
714 const float sin_h = g_rotated * inv_chroma_in;
715 const float chroma_boost =
d->chroma_global + scalar_product(opacities, chroma);
716 const float vibrance =
d->vibrance * (1.0f - powf(chroma_in, fabsf(
d->vibrance)));
717 const float chroma_factor =
MAX(1.f + chroma_boost + vibrance, 0.f);
718 float chroma_out = chroma_in * chroma_factor;
721 const float r_shifted = chroma_out * cos_h + 0.21902143f;
722 const float g_shifted = chroma_out * sin_h + 0.54371398f;
725 const float r_limit = -0.21902143f / cos_h;
726 chroma_out =
MIN(r_limit, chroma_out);
730 const float g_limit = -0.54371398f / sin_h;
731 chroma_out =
MIN(g_limit, chroma_out);
733 if(r_shifted + g_shifted > 1.f)
735 const float sum_limit = (1.f - 0.21902143f - 0.54371398f) / (cos_h + sin_h);
736 chroma_out =
MIN(sum_limit, chroma_out);
738 Yrg_v[1] = chroma_out * cos_h + 0.21902143f;
739 Yrg_v[2] = chroma_out * sin_h + 0.54371398f;
742 dt_aligned_pixel_simd_t LMS_work_v = Yrg_to_LMS_simd(Yrg_v);
745 RGB_v = LMS_to_gradingRGB_simd(LMS_work_v);
749 const dt_aligned_pixel_simd_t slopes_v
750 = opacities_comp[2] * (opacities_comp[0] + opacities[0] * shadows_v) + opacities[2] * highlights_v;
756 const dt_aligned_pixel_simd_t RGB_abs_v = dt_simd_abs(RGB_v) /
d->white_fulcrum;
759 RGB_v = dt_simd_copysign(dt_simd_pow(RGB_abs_v, midtones_v) *
d->white_fulcrum, RGB_v);
763 LMS_work_v = gradingRGB_to_LMS_simd(RGB_v);
764 Yrg_v = LMS_to_Yrg_simd(LMS_work_v);
767 Yrg_v[0] = powf(
MAX(Yrg_v[0] /
d->white_fulcrum, 0.f),
d->midtones_Y) *
d->white_fulcrum;
770 Yrg_v[0] =
d->grey_fulcrum * powf(Yrg_v[0] /
d->grey_fulcrum,
d->contrast);
772 LMS_work_v = Yrg_to_LMS_simd(Yrg_v);
773 dt_aligned_pixel_simd_t XYZ_D65_v = LMS_to_XYZ_simd(LMS_work_v);
778 dt_aligned_pixel_simd_t Jab_v = dt_XYZ_2_JzAzBz_simd(XYZ_D65_v);
781 float JC[2] = { Jab_v[0], dt_fast_hypotf(Jab_v[1], Jab_v[2]) };
782 const float h = atan2f(Jab_v[2], Jab_v[1]);
783 const float inv_chroma = (JC[1] > 0.f) ? 1.f / JC[1] : 0.f;
784 const float cos_H = Jab_v[1] * inv_chroma;
785 const float sin_H = Jab_v[2] * inv_chroma;
790 const float T = atan2f(JC[1], JC[0]);
791 const float sin_T = sinf(T);
792 const float cos_T = cosf(T);
800 const float boosts[2] = { 1.f +
d->brilliance_global + scalar_product(opacities, brilliance),
801 d->saturation_global + scalar_product(opacities, saturation) };
803 SO[0] = JC[0] * M_rot_dir[0][0] + JC[1] * M_rot_dir[0][1];
805 SO[0] =
MAX(SO[0] * boosts[0], 0.f);
808 JC[0] =
MAX(SO[0] * M_rot_inv[0][0] + SO[1] * M_rot_inv[0][1], 0.f);
809 JC[1] =
MAX(SO[0] * M_rot_inv[1][0] + SO[1] * M_rot_inv[1][1], 0.f);
814 const float sat = (JC[0] > 0.f) ?
soft_clip(JC[1] / JC[0], 0.8f * out_max_sat_h, out_max_sat_h)
816 const float max_C_at_sat = JC[0] * sat;
818 const float max_J_at_sat = (sat > 0.f) ? JC[1] / sat : JC[0];
819 JC[0] = (JC[0] + max_J_at_sat) / 2.f;
820 JC[1] = (JC[1] + max_C_at_sat) / 2.f;
825 const float d0 = 1.6295499532821566e-11f;
826 const float dd = -0.56f;
827 float Iz = JC[0] +
d0;
828 Iz /= (1.f + dd - dd * Iz);
832 = { { 1.0f, 0.1386050432715393f, 0.0580473161561189f, 0.0f },
833 { 1.0f, -0.1386050432715393f, -0.0580473161561189f, 0.0f },
834 { 1.0f, -0.0960192420263190f, -0.8118918960560390f, 0.0f } };
837 const dt_aligned_pixel_simd_t IzAzBz_v = { Iz, JC[1] * cos_H, JC[1] * sin_H, 0.f };
838 const dt_aligned_pixel_simd_t LMS_test_v = dt_mat3x4_mul_vec4(IzAzBz_v, jz_ai0, jz_ai1, jz_ai2);
842 if(LMS_test_v[0] < 0.f)
843 max_C =
MIN(-Iz / (
AI[0][1] * cos_H +
AI[0][2] * sin_H), max_C);
845 if(LMS_test_v[1] < 0.f)
846 max_C =
MIN(-Iz / (
AI[1][1] * cos_H +
AI[1][2] * sin_H), max_C);
848 if(LMS_test_v[2] < 0.f)
849 max_C =
MIN(-Iz / (
AI[2][1] * cos_H +
AI[2][2] * sin_H), max_C);
852 const dt_aligned_pixel_simd_t Jab_out_v = { JC[0], max_C * cos_H, max_C * sin_H, 0.f };
853 XYZ_D65_v = dt_JzAzBz_2_XYZ_simd(Jab_out_v);
857 dt_aligned_pixel_simd_t xyY_v = dt_XYZ_to_xyY_simd(XYZ_D65_v);
858 dt_aligned_pixel_simd_t JCH_v = xyY_to_dt_UCS_JCH_simd(xyY_v, L_white);
859 dt_aligned_pixel_simd_t HCB_v = dt_UCS_JCH_to_HCB_simd(JCH_v);
861 const float radius = dt_fast_hypotf(HCB_v[1], HCB_v[2]);
862 const float sin_T = (radius > 0.f) ? HCB_v[1] / radius : 0.f;
863 const float cos_T = (radius > 0.f) ? HCB_v[2] / radius : 0.f;
864 const float DT_ALIGNED_PIXEL M_rot_inv[2][2] = { { cos_T, sin_T }, { -sin_T, cos_T } };
866 float P =
MAX(HCB_v[1], FLT_MIN);
867 float W = sin_T * HCB_v[1] + cos_T * HCB_v[2];
869 const dt_aligned_pixel_simd_t sat_bri_v = dt_simd_max_zero((dt_aligned_pixel_simd_t){
870 1.f +
d->saturation_global + scalar_product(opacities, saturation),
871 1.f +
d->brilliance_global + scalar_product(opacities, brilliance),
874 float a = sat_bri_v[0];
875 const float b = sat_bri_v[1];
877 const float max_a = dt_fast_hypotf(
P,
W) /
P;
880 const float P_prime = (a - 1.f) *
P;
881 const float W_prime = sqrtf(sqf(
P) * (1.f - sqf(a)) + sqf(
W)) * b;
883 HCB_v[1] =
MAX(M_rot_inv[0][0] * P_prime + M_rot_inv[0][1] * W_prime, 0.f);
884 HCB_v[2] =
MAX(M_rot_inv[1][0] * P_prime + M_rot_inv[1][1] * W_prime, 0.f);
886 JCH_v = dt_UCS_HCB_to_JCH_simd(HCB_v);
887 const float max_colorfulness =
lookup_gamut(gamut_LUT, JCH_v[2]);
888 const float max_chroma = 15.932993652962535f * powf(JCH_v[0] * L_white, 0.6523997524738018f)
889 * powf(max_colorfulness, 0.6007557017508491f) / L_white;
890 const dt_aligned_pixel_simd_t JCH_gamut_boundary_v = { JCH_v[0], max_chroma, JCH_v[2], 0.f };
891 const dt_aligned_pixel_simd_t HSB_gamut_boundary_v = dt_UCS_JCH_to_HSB_simd(JCH_gamut_boundary_v);
892 dt_aligned_pixel_simd_t HSB_v = { HCB_v[0], (HCB_v[2] > 0.f) ? HCB_v[1] / HCB_v[2] : 0.f, HCB_v[2], 0.f };
893 HSB_v[1] =
soft_clip(HSB_v[1], 0.8f * HSB_gamut_boundary_v[1], HSB_gamut_boundary_v[1]);
894 JCH_v = dt_UCS_HSB_to_JCH_simd(HSB_v);
895 xyY_v = dt_UCS_JCH_to_xyY_simd(JCH_v, L_white);
896 XYZ_D65_v = dt_xyY_to_XYZ_simd(xyY_v);
899 dt_aligned_pixel_simd_t pix_out_v = dt_mat3x4_mul_vec4(XYZ_D65_v, output0, output1, output2);
902 const size_t i = idx / out_width;
903 const size_t j = idx -
i * out_width;
905 dt_aligned_pixel_simd_t color_v;
906 if(
i % checker_1 <
i % checker_2)
908 if(j % checker_1 < j % checker_2) color_v = checker_color_2_v;
909 else color_v = checker_color_1_v;
913 if(j % checker_1 < j % checker_2) color_v = checker_color_1_v;
914 else color_v = checker_color_2_v;
917 const float opacity = opacities[
d->mask_type];
918 const float opacity_comp = 1.0f - opacity;
920 dt_aligned_pixel_simd_t image_v = dt_simd_max_zero(pix_out_v);
921 if(
d->mask_preview_black_and_white)
923 const float gray = 0.3f * image_v[0] + 0.59f * image_v[1] + 0.11f * image_v[2];
924 image_v[0] = image_v[1] = image_v[2] = gray;
926 pix_out_v = opacity_comp * color_v + opacity * image_v;
931 pix_out_v = dt_simd_max_zero(pix_out_v);
932 pix_out_v[3] = pix_in_v[3];
934 dt_store_simd_nontemporal(pix_out, pix_out_v);
962 cl_mem dev_profile_info = NULL;
963 cl_mem dev_profile_lut = NULL;
965 cl_float *profile_lut_cl = NULL;
967 cl_mem input_matrix_cl = NULL;
968 cl_mem output_matrix_cl = NULL;
969 cl_mem gamut_LUT = NULL;
972 &dev_profile_info, &dev_profile_lut);
973 if(err != CL_SUCCESS)
goto error;
1010 float input_matrix_3x4[12];
1011 float output_matrix_3x4[12];
1021 const int mask_display =
d->mask_display;
1024 const int checker_2 = 2 * checker_1;
1025 const int mask_type =
d->mask_type;
1028 const cl_float2 hue_rotation_row_0 = {{ cosf(
d->hue_angle), -sinf(
d->hue_angle) }};
1029 const cl_float2 hue_rotation_row_1 = {{ sinf(
d->hue_angle), cosf(
d->hue_angle) }};
1070 if(err != CL_SUCCESS)
goto error;
1090 const int program = 8;
1108static inline float Delta_H(
const float h_1,
const float h_2)
1112 float diff = h_1 - h_2;
1128 d->checker_color_1[0] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker1/red"), 0.f, 1.f);
1129 d->checker_color_1[1] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker1/green"), 0.f, 1.f);
1130 d->checker_color_1[2] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker1/blue"), 0.f, 1.f);
1132 d->checker_color_2[0] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker2/red"), 0.f, 1.f);
1133 d->checker_color_2[1] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker2/green"), 0.f, 1.f);
1134 d->checker_color_2[2] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker2/blue"), 0.f, 1.f);
1135 d->checker_color_2[3] = 1.f;
1136 d->checker_size =
MAX(
dt_conf_get_int(
"plugins/darkroom/colorbalancergb/checker/size"), 2);
1137 d->mask_preview_black_and_white
1138 =
dt_conf_get_bool(
"plugins/darkroom/colorbalancergb/mask_preview/greyscaled");
1141 d->checker_color_1[3] =
d->mask_preview_black_and_white;
1148 d->vibrance =
p->vibrance;
1149 d->contrast = 1.0f +
p->contrast;
1150 d->grey_fulcrum =
p->grey_fulcrum;
1152 d->chroma_global =
p->chroma_global;
1153 d->chroma[0] =
p->chroma_shadows;
1154 d->chroma[1] =
p->chroma_midtones;
1155 d->chroma[2] =
p->chroma_highlights;
1158 d->saturation_global =
p->saturation_global;
1159 d->saturation[0] =
p->saturation_shadows;
1160 d->saturation[1] =
p->saturation_midtones;
1161 d->saturation[2] =
p->saturation_highlights;
1162 d->saturation[3] = 0.f;
1164 d->brilliance_global =
p->brilliance_global;
1165 d->brilliance[0] =
p->brilliance_shadows;
1166 d->brilliance[1] =
p->brilliance_midtones;
1167 d->brilliance[2] =
p->brilliance_highlights;
1168 d->brilliance[3] = 0.f;
1170 d->hue_angle =
M_PI *
p->hue_angle / 180.f;
1175 Ych_to_gradingRGB(Ych_norm, RGB_norm);
1180 Ych_to_gradingRGB(Ych,
d->global);
1181 for(
size_t c = 0; c < 3; c++)
d->global[c] = (
d->global[c] - RGB_norm[c]) + RGB_norm[c] *
p->global_Y;
1187 Ych_to_gradingRGB(Ych,
d->shadows);
1188 for(
size_t c = 0; c < 3; c++)
d->shadows[c] = 1.f + (
d->shadows[c] - RGB_norm[c]) +
p->shadows_Y;
1189 d->shadows_weight = 2.f +
p->shadows_weight * 2.f;
1195 Ych_to_gradingRGB(Ych,
d->highlights);
1196 for(
size_t c = 0; c < 3; c++)
d->highlights[c] = 1.f + (
d->highlights[c] - RGB_norm[c]) +
p->highlights_Y;
1197 d->highlights_weight = 2.f +
p->highlights_weight * 2.f;
1203 Ych_to_gradingRGB(Ych,
d->midtones);
1204 for(
size_t c = 0; c < 3; c++)
d->midtones[c] = 1.f / (1.f + (
d->midtones[c] - RGB_norm[c]));
1205 d->midtones_Y = 1.f / (1.f +
p->midtones_Y);
1206 d->white_fulcrum = exp2f(
p->white_fulcrum);
1207 d->midtones_weight = sqf(
d->shadows_weight) * sqf(
d->highlights_weight) /
1208 (sqf(
d->shadows_weight) + sqf(
d->highlights_weight));
1209 d->mask_grey_fulcrum = powf(
p->mask_grey_fulcrum, 0.4101205819200422f);
1212 if(
p->saturation_formula !=
d->saturation_formula)
d->lut_inited =
FALSE;
1213 d->saturation_formula =
p->saturation_formula;
1220 if(work_profile !=
d->work_profile)
1223 d->work_profile = work_profile;
1234 for(
size_t k = 0;
k <
LUT_ELEM;
k++) LUT_saturation[
k] = 0.f;
1247 for(
size_t b = 0; b <
STEPS; b++)
1250 (float)b / (
float)(
STEPS - 1), 0.f };
1252 float saturation = 0.f;
1255 dot_product(
rgb, input_matrix,
XYZ);
1258 dt_XYZ_2_JzAzBz(
XYZ, Jab);
1261 Jch[1] = dt_fast_hypotf(Jab[2], Jab[1]);
1262 Jch[2] = atan2f(Jab[2], Jab[1]);
1264 saturation = (Jch[0] > 0.f) ? Jch[1] / Jch[0] : 0.f;
1268 LUT_saturation[index] = fmaxf(saturation, LUT_saturation[index]);
1273 d->gamut_LUT[
k] = (LUT_saturation[
k - 2] + LUT_saturation[
k - 1] + LUT_saturation[
k] + LUT_saturation[
k + 1] + LUT_saturation[
k + 2]) / 5.f;
1276 d->gamut_LUT[0] = (LUT_saturation[
LUT_ELEM - 2] + LUT_saturation[
LUT_ELEM - 1] + LUT_saturation[0] + LUT_saturation[1] + LUT_saturation[2]) / 5.f;
1277 d->gamut_LUT[1] = (LUT_saturation[
LUT_ELEM - 1] + LUT_saturation[0] + LUT_saturation[1] + LUT_saturation[2] + LUT_saturation[3]) / 5.f;
1278 d->gamut_LUT[
LUT_ELEM - 1] = (LUT_saturation[
LUT_ELEM - 3] + LUT_saturation[
LUT_ELEM - 2] + LUT_saturation[
LUT_ELEM - 1] + LUT_saturation[0] + LUT_saturation[1]) / 5.f;
1283 dt_aligned_pixel_t D65_xyY = { 0.31269999999999992f, 0.32899999999999996f , 1.f, 0.f };
1291 dot_product(RGB_red, input_matrix, XYZ_red);
1292 dot_product(RGB_green, input_matrix, XYZ_green);
1293 dot_product(RGB_blue, input_matrix, XYZ_blue);
1301 const float h_red = atan2f(xyY_red[1] - D65_xyY[1], xyY_red[0] - D65_xyY[0]);
1302 const float h_green = atan2f(xyY_green[1] - D65_xyY[1], xyY_green[0] - D65_xyY[0]);
1303 const float h_blue = atan2f(xyY_blue[1] - D65_xyY[1], xyY_blue[0] - D65_xyY[0]);
1305 float *
const restrict dt_UCS_LUT =
d->gamut_LUT;
1309 for(
int i = 0;
i < 50 * 360;
i++)
1311 const float angle = -
M_PI_F + ((float)
i) / (50.f * 360.f) * 2.f *
M_PI_F;
1312 const float tan_angle = tanf(angle);
1314 const float t_1 =
Delta_H(angle, h_blue) /
Delta_H(h_red, h_blue);
1315 const float t_2 =
Delta_H(angle, h_red) /
Delta_H(h_green, h_red);
1316 const float t_3 =
Delta_H(angle, h_green) /
Delta_H(h_blue, h_green);
1321 if(t_1 == CLAMP(t_1, 0, 1))
1323 const float t = (D65_xyY[1] - xyY_blue[1] + tan_angle * (xyY_blue[0] - D65_xyY[0]))
1324 / (xyY_red[1] - xyY_blue[1] + tan_angle * (xyY_blue[0] - xyY_red[0]));
1325 x_t = xyY_blue[0] +
t * (xyY_red[0] - xyY_blue[0]);
1326 y_t = xyY_blue[1] +
t * (xyY_red[1] - xyY_blue[1]);
1328 else if(t_2 == CLAMP(t_2, 0, 1))
1330 const float t = (D65_xyY[1] - xyY_red[1] + tan_angle * (xyY_red[0] - D65_xyY[0]))
1331 / (xyY_green[1] - xyY_red[1] + tan_angle * (xyY_red[0] - xyY_green[0]));
1332 x_t = xyY_red[0] +
t * (xyY_green[0] - xyY_red[0]);
1333 y_t = xyY_red[1] +
t * (xyY_green[1] - xyY_red[1]);
1335 else if(t_3 == CLAMP(t_3, 0, 1))
1337 const float t = (D65_xyY[1] - xyY_green[1] + tan_angle * (xyY_green[0] - D65_xyY[0]))
1338 / (xyY_blue[1] - xyY_green[1] + tan_angle * (xyY_green[0] - xyY_blue[0]));
1339 x_t = xyY_green[0] +
t * (xyY_blue[0] - xyY_green[0]);
1340 y_t = xyY_green[1] +
t * (xyY_blue[1] - xyY_green[1]);
1345 float UV_star_prime[2];
1349 const float H = atan2f(UV_star_prime[1], UV_star_prime[0]) * 180.f /
M_PI_F;
1350 const float H_round = roundf(
H);
1351 if(fabsf(
H - H_round) < 0.02f)
1353 int index = (int)(H_round + 180);
1354 index += (index < 0) ? 360 : 0;
1355 index -= (index > 359) ? 360 : 0;
1357 dt_UCS_LUT[index] = UV_star_prime[0] * UV_star_prime[0] + UV_star_prime[1] * UV_star_prime[1];
1363 d->lut_inited =
TRUE;
1388 d->gamut_LUT = NULL;
1403 work_profile->unbounded_coeffs_in, work_profile->
lutsize,
1409 Ych[2] = 2.f *
M_PI + Ych[2];
1423 hue = (hue > 360.f) ? hue - 360.f : hue;
1426 if(picker ==
g->global_H)
1429 p->global_C = Ych[1] * Ych[0];
1433 else if(picker ==
g->shadows_H)
1436 p->shadows_C = Ych[1] * Ych[0];
1440 else if(picker ==
g->midtones_H)
1442 p->midtones_H = hue;
1443 p->midtones_C = Ych[1] * Ych[0];
1447 else if(picker ==
g->highlights_H)
1449 p->highlights_H = hue;
1450 p->highlights_C = Ych[1] * Ych[0];
1454 else if(picker ==
g->white_fulcrum)
1456 p->white_fulcrum = log2f(max_Ych[0]);
1459 else if(picker ==
g->grey_fulcrum)
1461 p->grey_fulcrum = Ych[0];
1465 fprintf(stderr,
"[colorbalancergb] unknown color picker\n");
1480 const float *
const restrict in = (
const float *)
i;
1484 for(
size_t k = 0;
k < (size_t)roi_out->
width * roi_out->
height * 4;
k += 4)
1488 if(isfinite(Ych[0]))
1489 max_Y = fmaxf(max_Y, Ych[0]);
1492 p->white_fulcrum = log2f(fmaxf(max_Y, 1e-6f));
1498 const float x_min = 0;
1499 const float x_max = 1;
1500 const float x_range = x_max - x_min;
1506 const float x = x_min + stop * x_range;
1512 Ych_to_XYZ(Ych,
XYZ);
1513 dt_XYZ_to_Rec709_D65(
XYZ,
RGB);
1514 const float max_RGB = fmaxf(fmaxf(
RGB[0],
RGB[1]),
RGB[2]);
1515 for(
size_t c = 0; c < 3; c++)
RGB[c] = powf(
RGB[c] / max_RGB, 1.f / 2.2f);
1519 gtk_widget_queue_draw(w);
1528 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
gui->
off),
TRUE);
1536 g->mask_display = !
g->mask_display;
1540 if(togglebutton ==
g->shadows_weight)
g->mask_type =
MASK_SHADOWS;
1541 if(togglebutton ==
g->mask_grey_fulcrum)
g->mask_type =
MASK_MIDTONES;
1563 const float shadows_weight = 2.f +
p->shadows_weight * 2.f;
1564 const float highlights_weight = 2.f +
p->highlights_weight * 2.f;
1567 GtkAllocation allocation;
1568 gtk_widget_get_allocation(widget, &allocation);
1569 GtkStyleContext *context = gtk_widget_get_style_context(widget);
1571 cairo_surface_t *cst =
1573 PangoFontDescription *desc =
1575 cairo_t *cr = cairo_create(cst);
1576 PangoLayout *layout = pango_cairo_create_layout(cr);
1578 const gint font_size = pango_font_description_get_size(desc);
1579 pango_font_description_set_size(desc, 0.95 * font_size);
1580 pango_layout_set_font_description(layout, desc);
1587 snprintf(text,
sizeof(text),
"X");
1588 pango_layout_set_text(layout, text, -1);
1589 pango_layout_get_pixel_extents(layout, &ink, NULL);
1590 const float line_height = ink.height;
1593 const float margin_top = inset;
1594 const float margin_bottom = line_height + 2 * inset;
1595 const float margin_left = line_height + inset;
1596 const float margin_right = 0;
1598 const float graph_width = allocation.width - margin_right - margin_left;
1599 const float graph_height = allocation.height - margin_bottom - margin_top;
1601 gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);
1604 cairo_pattern_t *grad;
1605 grad = cairo_pattern_create_linear(margin_left, 0.0, graph_width, 0.0);
1607 cairo_set_line_width(cr, 0.0);
1608 cairo_rectangle(cr, margin_left, graph_height + 2 * inset, graph_width, line_height);
1609 cairo_set_source(cr, grad);
1611 cairo_pattern_destroy(grad);
1614 const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, line_height);
1615 unsigned char *data = malloc(stride * graph_height);
1616 cairo_surface_t *surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, (
size_t)line_height, (
size_t)graph_height, stride);
1619 const size_t checker_2 = 2 * checker_1;
1621 for(
size_t i = 0;
i < (size_t)graph_height;
i++)
1622 for(
size_t j = 0; j < (size_t)line_height; j++)
1624 const size_t k = ((
i * (size_t)line_height) + j) * 4;
1625 unsigned char color;
1626 const float alpha = (float)
i / graph_height;
1627 if(
i % checker_1 <
i % checker_2)
1629 if(j % checker_1 < j % checker_2)
color = 150;
1634 if(j % checker_1 < j % checker_2)
color = 100;
1638 for(
size_t c = 0; c < 4; ++c) data[
k + c] =
color * alpha;
1639 data[
k+3] = alpha * 255;
1642 cairo_set_source_surface(cr, surface, 0, margin_top);
1645 cairo_surface_destroy(surface);
1648 cairo_translate(cr, margin_left, margin_top);
1649 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
1652 cairo_rectangle(cr, 0, 0, graph_width, graph_height);
1653 cairo_fill_preserve(cr);
1657 const float midtones_weight
1658 = sqf(shadows_weight) * sqf(highlights_weight) / (sqf(shadows_weight) + sqf(highlights_weight));
1659 const float mask_grey_fulcrum = powf(
p->mask_grey_fulcrum, 0.4101205819200422f);
1666 const float Y =
k / (float)(
LUT_ELEM - 1);
1668 opacity_masks(Y, shadows_weight, highlights_weight, midtones_weight, mask_grey_fulcrum, output, NULL);
1669 for(
size_t c = 0; c < 3; c++) LUT[c][
k] = output[c];
1675 for(
size_t c = 0; c < 3; c++)
1677 GdkRGBA line_color = { fg_color.red * (1. - (2 - c) / 4.),
1678 fg_color.green * (1. - (2 - c) / 4.),
1679 fg_color.blue * (1. - (2 - c) / 4.),
1683 cairo_move_to(cr, 0, (1.f - LUT[c][0]) * graph_height);
1686 const float x = (float)
k / (
float)(
LUT_ELEM - 1) * graph_width;
1687 const float y = (1.f - LUT[c][
k]) * graph_height;
1688 cairo_line_to(cr,
x, y);
1698 pango_font_description_set_size(desc, font_size);
1699 pango_layout_set_font_description(layout, desc);
1702 cairo_set_source_surface(crf, cst, 0, 0);
1704 cairo_surface_destroy(cst);
1705 g_object_unref(layout);
1706 pango_font_description_free(desc);
1730 if(
IS_NULL_PTR(w) || w ==
g->shadows_weight || w ==
g->highlights_weight || w ==
g->mask_grey_fulcrum)
1731 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
1824 gtk_widget_set_tooltip_text(
g->hue_angle, _(
"rotate all hues by an angle, at the same luminance"));
1830 gtk_widget_set_tooltip_text(
g->vibrance, _(
"increase colorfulness mostly on low-chroma colors"));
1836 gtk_widget_set_tooltip_text(
g->contrast, _(
"increase the contrast at constant chromaticity"));
1844 gtk_widget_set_tooltip_text(
g->chroma_global, _(
"increase colorfulness at same luminance globally"));
1849 gtk_widget_set_tooltip_text(
g->chroma_shadows, _(
"increase colorfulness at same luminance mostly in shadows"));
1854 gtk_widget_set_tooltip_text(
g->chroma_midtones, _(
"increase colorfulness at same luminance mostly in mid-tones"));
1859 gtk_widget_set_tooltip_text(
g->chroma_highlights, _(
"increase colorfulness at same luminance mostly in highlights"));
1866 gtk_widget_set_tooltip_text(
g->saturation_global, _(
"add or remove saturation by an absolute amount"));
1871 gtk_widget_set_tooltip_text(
g->saturation_shadows, _(
"increase or decrease saturation proportionally to the original pixel saturation"));
1876 gtk_widget_set_tooltip_text(
g->saturation_midtones, _(
"increase or decrease saturation proportionally to the original pixel saturation"));
1881 gtk_widget_set_tooltip_text(
g->saturation_highlights, _(
"increase or decrease saturation proportionally to the original pixel saturation"));
1888 gtk_widget_set_tooltip_text(
g->brilliance_global, _(
"add or remove brilliance by an absolute amount"));
1893 gtk_widget_set_tooltip_text(
g->brilliance_shadows, _(
"increase or decrease brilliance proportionally to the original pixel brilliance"));
1898 gtk_widget_set_tooltip_text(
g->brilliance_midtones, _(
"increase or decrease brilliance proportionally to the original pixel brilliance"));
1903 gtk_widget_set_tooltip_text(
g->brilliance_highlights, _(
"increase or decrease brilliance proportionally to the original pixel brilliance"));
1914 gtk_widget_set_tooltip_text(
g->global_Y, _(
"global luminance offset"));
1919 gtk_widget_set_tooltip_text(
g->global_H, _(
"hue of the global color offset"));
1925 gtk_widget_set_tooltip_text(
g->global_C, _(
"chroma of the global color offset"));
1933 gtk_widget_set_tooltip_text(
g->shadows_Y, _(
"luminance gain in shadows"));
1938 gtk_widget_set_tooltip_text(
g->shadows_H, _(
"hue of the color gain in shadows"));
1944 gtk_widget_set_tooltip_text(
g->shadows_C, _(
"chroma of the color gain in shadows"));
1952 gtk_widget_set_tooltip_text(
g->highlights_Y, _(
"luminance gain in highlights"));
1957 gtk_widget_set_tooltip_text(
g->highlights_H, _(
"hue of the color gain in highlights"));
1963 gtk_widget_set_tooltip_text(
g->highlights_C, _(
"chroma of the color gain in highlights"));
1971 gtk_widget_set_tooltip_text(
g->midtones_Y, _(
"luminance exponent in mid-tones"));
1976 gtk_widget_set_tooltip_text(
g->midtones_H, _(
"hue of the color exponent in mid-tones"));
1982 gtk_widget_set_tooltip_text(
g->midtones_C, _(
"chroma of the color exponent in mid-tones"));
1988 gtk_widget_set_tooltip_text(
g->saturation_formula, _(
"choose in which uniform color space the saturation is computed."));
1992 g->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
1993 gtk_widget_set_hexpand(GTK_WIDGET(
g->area),
TRUE);
1994 g_object_set_data(G_OBJECT(
g->area),
"iop-instance", self);
1996 gtk_box_pack_start(GTK_BOX(self->
gui->
widget),
1998 "plugins/darkroom/colorbalancergb/graphheight", 200, 100),
2006 gtk_widget_set_tooltip_text(
g->shadows_weight, _(
"weight of the shadows over the whole tonal range"));
2009 g_signal_connect(G_OBJECT(
g->shadows_weight),
"quad-pressed", G_CALLBACK(
mask_callback), self);
2014 gtk_widget_set_tooltip_text(
g->mask_grey_fulcrum, _(
"position of the middle-gray reference for masking"));
2017 g_signal_connect(G_OBJECT(
g->mask_grey_fulcrum),
"quad-pressed", G_CALLBACK(
mask_callback), self);
2022 gtk_widget_set_tooltip_text(
g->highlights_weight, _(
"weights of highlights over the whole tonal range"));
2025 g_signal_connect(G_OBJECT(
g->highlights_weight),
"quad-pressed", G_CALLBACK(
mask_callback), self);
2032 gtk_widget_set_tooltip_text(
g->white_fulcrum, _(
"peak white luminance value used to normalize the power function"));
2038 gtk_widget_set_tooltip_text(
g->grey_fulcrum, _(
"peak gray luminance value used to normalize the power function"));
2074 Ych_to_XYZ(Ych,
XYZ);
2075 dt_XYZ_to_Rec709_D65(
XYZ,
RGB);
2076 const float max_RGB = fmaxf(fmaxf(
RGB[0],
RGB[1]),
RGB[2]);
2077 for(
size_t c = 0; c < 3; c++)
RGB[c] = powf(
RGB[c] / max_RGB, 1.f / 2.2f);
2083 const float Y = 0.f + stop;
void dt_gui_set_pango_resolution(PangoLayout *layout)
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)
void dt_bauhaus_slider_set_stop(GtkWidget *widget, float stop, float r, float g, float b)
void dt_bauhaus_slider_set_feedback(GtkWidget *widget, int feedback)
void dt_bauhaus_widget_set_quad_toggle(GtkWidget *widget, int toggle)
void dt_bauhaus_widget_set_quad_active(GtkWidget *widget, int active)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
void dt_bauhaus_widget_set_quad_paint(GtkWidget *widget, dt_bauhaus_quad_paint_f f, int paint_flags, void *paint_data)
#define DT_BAUHAUS_SLIDER_MAX_STOPS
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static void XYZ_D50_to_D65(const dt_aligned_pixel_t XYZ_in, dt_aligned_pixel_t XYZ_out)
static const dt_colormatrix_t XYZ_D65_to_D50_CAT16
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)
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static gboolean area_scroll_callback(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
const char ** description(struct dt_iop_module_t *self)
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
static float Delta_H(const float h_1, const float h_2)
void gui_reset(dt_iop_module_t *self)
static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
dt_iop_colorbalancrgb_saturation_t
@ DT_COLORBALANCE_SATURATION_JZAZBZ
@ DT_COLORBALANCE_SATURATION_DTUCS
void gui_update(dt_iop_module_t *self)
static float soft_clip(const float x, const float soft_threshold, const float hard_threshold)
void gui_init(dt_iop_module_t *self)
void pipe_RGB_to_Ych(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_aligned_pixel_t RGB, dt_aligned_pixel_t Ych)
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
static void mask_callback(GtkWidget *togglebutton, dt_iop_module_t *self)
struct dt_iop_colorbalance_global_data_t dt_iop_colorbalancergb_global_data_t
void cleanup_global(dt_iop_module_so_t *module)
void cleanup_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
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)
dt_iop_colorbalancergb_mask_data_t
void gui_cleanup(struct dt_iop_module_t *self)
void init_presets(dt_iop_module_so_t *self)
void init_pipe(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static float lookup_gamut(const float *const gamut_lut, const float x)
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)
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)
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
static void paint_chroma_slider(GtkWidget *w, const float hue)
gboolean runtime_data_hash(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
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)
free parameters build with the previous function.
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)
build the required parameters for a kernel that uses a profile info.
static void xyY_to_dt_UCS_UV(const float4 xyY, float UV_star_prime[2])
static float Y_to_dt_UCS_L_star(const float Y)
static float4 dt_XYZ_to_xyY(const float4 XYZ)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
static dt_aligned_pixel_t xyY
static dt_aligned_pixel_t rgb
static dt_aligned_pixel_t XYZ
static dt_aligned_pixel_t XYZ_D65
static dt_aligned_pixel_t XYZ_D50
const dt_colormatrix_t AI
const dt_colormatrix_t dt_aligned_pixel_t out
static dt_aligned_pixel_t RGB
int dt_conf_get_bool(const char *name)
float dt_conf_get_float(const char *name)
Float for name, clamped to its declared bounds.
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_resync_history_main(dev)
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)
@ DT_DEV_PIXELPIPE_DISPLAY_PASSTHRU
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
static void set_color(cairo_t *cr, GdkRGBA color)
static void dt_cairo_perceptual_gradient(cairo_pattern_t *grad, double alpha)
void dt_gui_presets_update_ldr(const char *name, dt_dev_operation_t op, const int32_t version, const int ldrflag)
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
@ IOP_FLAGS_INCLUDE_IN_STYLES
@ IOP_FLAGS_SUPPORTS_BLENDING
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_ui_section_label_new(const gchar *str)
static const dt_dev_pixelpipe_t * pipe
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t * piece
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
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)
#define DT_ALIGNED_PIXEL
Align a 4-float pixel on 16 bytes, enough for SSE. Same struct-member caveat as DT_ALIGNED_ARRAY,...
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
static float * dt_alloc_align_float(size_t pixels)
Allocate pixels floats, cacheline-aligned and marked as such.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
GtkNotebook * dt_ui_notebook_new()
void dt_ui_notebook_set_picker_owner(GtkNotebook *notebook, gpointer owner)
Register an opaque owner for a GtkNotebook's page switches, and report every "switch_page" to the hos...
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
int dt_opencl_create_kernel(const int prog, const char *name)
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
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)
void * dt_opencl_copy_host_to_device(const int devid, void *host, const int width, const int height, const int bpp)
void dt_opencl_release_mem_object(cl_mem mem)
#define dt_omploop_sfence()
#define __OMP_DECLARE_SIMD__(...)
#define __OMP_PARALLEL_FOR__(...)
#define __OMP_PARALLEL_FOR_SIMD__(...)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
The device-side view of a dt_iop_order_iccprofile_info_t: the scalar fields only.
dt_dev_pixelpipe_type_t type
dt_iop_buffer_type_t datatype
int kernel_colorbalance_rgb
dt_aligned_pixel_t checker_color_1
struct dt_iop_order_iccprofile_info_t * work_profile
dt_aligned_pixel_t global
dt_aligned_pixel_t saturation
gboolean mask_preview_black_and_white
dt_iop_colorbalancrgb_saturation_t saturation_formula
dt_aligned_pixel_t chroma
dt_aligned_pixel_t highlights
dt_iop_colorbalancergb_mask_data_t mask_type
dt_aligned_pixel_t brilliance
dt_aligned_pixel_t midtones
dt_aligned_pixel_t shadows
dt_aligned_pixel_t checker_color_2
GtkWidget * brilliance_midtones
GtkWidget * brilliance_shadows
GtkWidget * shadows_weight
GtkWidget * chroma_shadows
GtkWidget * saturation_highlights
GtkWidget * highlights_weight
GtkWidget * saturation_midtones
GtkWidget * saturation_formula
GtkWidget * white_fulcrum
GtkWidget * chroma_midtones
GtkWidget * saturation_shadows
GtkWidget * saturation_global
GtkWidget * brilliance_global
GtkWidget * chroma_highlights
GtkWidget * brilliance_highlights
dt_iop_colorbalancergb_mask_data_t mask_type
GtkWidget * mask_grey_fulcrum
GtkWidget * chroma_global
float saturation_highlights
float brilliance_midtones
float saturation_midtones
float brilliance_highlights
dt_iop_colorbalancrgb_saturation_t saturation_formula
dt_iop_global_data_t * data
dt_iop_params_t * default_params
struct dt_iop_module_gui_t * gui
struct dt_develop_t * dev
dt_iop_global_data_t * global_data
dt_aligned_pixel_t picked_color_max
dt_aligned_pixel_t picked_color
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
int nonlinearlut
Non-zero when the profile has tone curves at all; tested as a boolean everywhere, but it is really th...
int lutsize
Entry count of each of the six LUTs. Always 65536 in practice: both callers of dt_ioppr_init_profile_...
dt_colormatrix_t matrix_out
XYZ (D50) -> RGB, row-major; the inverse of matrix_in.
float * lut_in[3]
Per-channel encoded -> linear tone curve, lutsize entries each, sampled over [0,1]....
dt_colormatrix_t matrix_in_transposed
dt_colormatrix_t matrix_in
RGB -> XYZ (D50), row-major. matrix_in[1][*] is the luminance row. NaN in [0][0] marks the whole prof...
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__