75#define ANGLE_SHIFT -30.f
76#define DEG_TO_RAD(x) ((x + ANGLE_SHIFT) * M_PI / 180.f)
77#define RAD_TO_DEG(x) (x * 180.f / M_PI - ANGLE_SHIFT)
201 return _(
"color _balance");
206 return _(
"offset power slope|cdl|color grading|contrast|chroma_highlights|hue|vibrance|saturation");
212 _(
"corrective or creative"),
213 _(
"linear, RGB, scene-referred"),
214 _(
"non-linear, RGB"),
215 _(
"non-linear, RGB, scene-referred"));
242 const int new_version)
244 if(old_version == 1 && new_version == 5)
246 typedef struct dt_iop_colorbalancergb_params_v1_t
260 float shadows_weight;
262 float highlights_weight;
263 float chroma_shadows;
264 float chroma_highlights;
266 float chroma_midtones;
267 float saturation_global;
268 float saturation_highlights;
269 float saturation_midtones;
270 float saturation_shadows;
272 } dt_iop_colorbalancergb_params_v1_t;
278 memcpy(new_params, old_params,
sizeof(dt_iop_colorbalancergb_params_v1_t));
282 n->mask_grey_fulcrum = 0.1845f;
284 n->grey_fulcrum = 0.1845f;
291 if(old_version == 2 && new_version == 5)
293 typedef struct dt_iop_colorbalancergb_params_v2_t
308 float shadows_weight;
310 float highlights_weight;
311 float chroma_shadows;
312 float chroma_highlights;
314 float chroma_midtones;
315 float saturation_global;
316 float saturation_highlights;
317 float saturation_midtones;
318 float saturation_shadows;
322 float brilliance_global;
323 float brilliance_highlights;
324 float brilliance_midtones;
325 float brilliance_shadows;
327 } dt_iop_colorbalancergb_params_v2_t;
333 memcpy(new_params, old_params,
sizeof(dt_iop_colorbalancergb_params_v2_t));
338 n->grey_fulcrum = 0.1845f;
344 if(old_version == 3 && new_version == 5)
346 typedef struct dt_iop_colorbalancergb_params_v3_t
361 float shadows_weight;
363 float highlights_weight;
364 float chroma_shadows;
365 float chroma_highlights;
367 float chroma_midtones;
368 float saturation_global;
369 float saturation_highlights;
370 float saturation_midtones;
371 float saturation_shadows;
375 float brilliance_global;
376 float brilliance_highlights;
377 float brilliance_midtones;
378 float brilliance_shadows;
381 float mask_grey_fulcrum;
383 } dt_iop_colorbalancergb_params_v3_t;
389 memcpy(new_params, old_params,
sizeof(dt_iop_colorbalancergb_params_v3_t));
393 n->grey_fulcrum = 0.1845f;
399 if(old_version == 4 && new_version == 5)
401 typedef struct dt_iop_colorbalancergb_params_v4_t
416 float shadows_weight;
418 float highlights_weight;
419 float chroma_shadows;
420 float chroma_highlights;
422 float chroma_midtones;
423 float saturation_global;
424 float saturation_highlights;
425 float saturation_midtones;
426 float saturation_shadows;
430 float brilliance_global;
431 float brilliance_highlights;
432 float brilliance_midtones;
433 float brilliance_shadows;
436 float mask_grey_fulcrum;
443 } dt_iop_colorbalancergb_params_v4_t;
449 memcpy(new_params, old_params,
sizeof(dt_iop_colorbalancergb_params_v4_t));
467 p.highlights_weight = 1.f;
468 p.mask_grey_fulcrum = 0.1845f;
469 p.grey_fulcrum = 0.1845f;
470 p.white_fulcrum = 1.f;
474 p.chroma_global = 0.2f;
475 p.saturation_shadows = 0.1f;
476 p.saturation_midtones = 0.05f;
477 p.saturation_highlights = -0.05f;
482 p.chroma_global = 0.f;
484 p.saturation_global = 0.2f;
485 p.saturation_shadows = 0.30f;
486 p.saturation_midtones = 0.f;
487 p.saturation_highlights = 0.f;
490 p.saturation_global = 0.2f;
491 p.saturation_shadows = 0.5f;
492 p.saturation_midtones = 0.f;
493 p.saturation_highlights = 0.0f;
496 p.saturation_global = 0.2f;
497 p.saturation_shadows = 0.25f;
498 p.saturation_midtones = 0.f;
499 p.saturation_highlights = 0.0f;
508__OMP_DECLARE_SIMD__(aligned(output, output_comp: 16) uniform(shadows_weight, midtones_weight, highlights_weight))
509static inline
void opacity_masks(const float
x,
510 const float shadows_weight, const float highlights_weight,
511 const float midtones_weight, const float mask_grey_fulcrum,
514 const float x_offset = (
x - mask_grey_fulcrum);
515 const float x_offset_norm = x_offset / mask_grey_fulcrum;
516 const float alpha = 1.f / (1.f + expf(x_offset_norm * shadows_weight));
517 const float beta = 1.f / (1.f + expf(-x_offset_norm * highlights_weight));
518 const float alpha_comp = 1.f - alpha;
519 const float beta_comp = 1.f - beta;
520 const float gamma = expf(-sqf(x_offset) * midtones_weight / 4.f) * sqf(alpha_comp) * sqf(beta_comp) * 8.f;
521 const float gamma_comp = 1.f - gamma;
530 output_comp[0] = alpha_comp;
531 output_comp[1] = gamma_comp;
532 output_comp[2] = beta_comp;
533 output_comp[3] = 0.f;
537static inline float soft_clip(
const float x,
const float soft_threshold,
const float hard_threshold)
541 const float norm = hard_threshold - soft_threshold;
542 return (
x > soft_threshold) ? soft_threshold + (1.f - expf(-(
x - soft_threshold) / norm)) * norm :
x;
546static inline float lookup_gamut(
const float *
const gamut_lut,
const float x)
554 float x_prev = floorf(x_test);
555 float x_next = ceilf(x_test);
559 int xi = (int)x_prev;
563 int xii = (int)x_next;
565 else if(xii >
LUT_ELEM - 1) xii = 0;
568 const float y_prev = gamut_lut[xi];
569 const float y_next = gamut_lut[xii];
577 out += (x_test - x_prev) * (y_next - y_prev) / (x_next - x_prev);
631 const float *
const restrict in = __builtin_assume_aligned(((
const float *
const restrict)ivoid), 64);
632 float *
const restrict
out = __builtin_assume_aligned(((
float *
const restrict)
ovoid), 64);
633 const float *
const restrict gamut_LUT = __builtin_assume_aligned(((
const float *
const restrict)
d->gamut_LUT), 64);
635 const float *
const restrict global = __builtin_assume_aligned((
const float *
const restrict)
d->global, 16);
636 const float *
const restrict highlights = __builtin_assume_aligned((
const float *
const restrict)
d->highlights, 16);
637 const float *
const restrict shadows = __builtin_assume_aligned((
const float *
const restrict)
d->shadows, 16);
638 const float *
const restrict midtones = __builtin_assume_aligned((
const float *
const restrict)
d->midtones, 16);
640 const float *
const restrict chroma = __builtin_assume_aligned((
const float *
const restrict)
d->chroma, 16);
641 const float *
const restrict saturation = __builtin_assume_aligned((
const float *
const restrict)
d->saturation, 16);
642 const float *
const restrict brilliance = __builtin_assume_aligned((
const float *
const restrict)
d->brilliance, 16);
644 const dt_aligned_pixel_simd_t input0 = dt_colormatrix_row_to_simd(input_matrix_transposed, 0);
645 const dt_aligned_pixel_simd_t input1 = dt_colormatrix_row_to_simd(input_matrix_transposed, 1);
646 const dt_aligned_pixel_simd_t input2 = dt_colormatrix_row_to_simd(input_matrix_transposed, 2);
647 const dt_aligned_pixel_simd_t output0 = dt_colormatrix_row_to_simd(output_matrix_transposed, 0);
648 const dt_aligned_pixel_simd_t output1 = dt_colormatrix_row_to_simd(output_matrix_transposed, 1);
649 const dt_aligned_pixel_simd_t output2 = dt_colormatrix_row_to_simd(output_matrix_transposed, 2);
651 const dt_aligned_pixel_simd_t global_v = dt_load_simd_aligned(global);
652 const dt_aligned_pixel_simd_t highlights_v = dt_load_simd_aligned(highlights);
653 const dt_aligned_pixel_simd_t shadows_v = dt_load_simd_aligned(shadows);
654 const dt_aligned_pixel_simd_t midtones_v = dt_load_simd_aligned(midtones);
655 const dt_aligned_pixel_simd_t jz_ai0 = dt_colormatrix_row_to_simd(AI_transposed, 0);
656 const dt_aligned_pixel_simd_t jz_ai1 = dt_colormatrix_row_to_simd(AI_transposed, 1);
657 const dt_aligned_pixel_simd_t jz_ai2 = dt_colormatrix_row_to_simd(AI_transposed, 2);
659 const gboolean mask_display =
d->mask_display;
661 const dt_aligned_pixel_simd_t checker_color_1_v = dt_load_simd(
d->checker_color_1);
662 const dt_aligned_pixel_simd_t checker_color_2_v = dt_load_simd(
d->checker_color_2);
663 const size_t checker_1
665 const size_t checker_2 = 2 * checker_1;
666 const size_t npixels = (size_t)roi_out->
width * roi_out->
height;
667 const size_t out_width = roi_out->
width;
671 { cosf(
d->hue_angle), -sinf(
d->hue_angle) },
672 { sinf(
d->hue_angle), cosf(
d->hue_angle) },
675 for(
size_t idx = 0; idx < npixels; idx++)
677 const size_t k = idx * 4;
678 const float *
const restrict pix_in = __builtin_assume_aligned(in +
k, 16);
679 float *
const restrict pix_out = __builtin_assume_aligned(
out +
k, 16);
680 const dt_aligned_pixel_simd_t pix_in_v = dt_load_simd_aligned(pix_in);
682 dt_aligned_pixel_simd_t RGB_v = dt_simd_max_zero(pix_in_v);
684 const dt_aligned_pixel_simd_t LMS_v = dt_mat3x4_mul_vec4(RGB_v, input0, input1, input2);
685 dt_aligned_pixel_simd_t Yrg_v = LMS_to_Yrg_simd(LMS_v);
686 Yrg_v[0] =
MAX(Yrg_v[0], 0.f);
689 opacity_masks(powf(Yrg_v[0], 0.4101205819200422f),
d->shadows_weight,
d->highlights_weight,
690 d->midtones_weight,
d->mask_grey_fulcrum, opacities, opacities_comp);
694 const float r_centered = Yrg_v[1] - 0.21902143f;
695 const float g_centered = Yrg_v[2] - 0.54371398f;
696 const float r_rotated = hue_rotation_matrix[0][0] * r_centered + hue_rotation_matrix[0][1] * g_centered;
697 const float g_rotated = hue_rotation_matrix[1][0] * r_centered + hue_rotation_matrix[1][1] * g_centered;
698 const float chroma_in = dt_fast_hypotf(g_rotated, r_rotated);
699 const float inv_chroma_in = (chroma_in > 0.f) ? 1.f / chroma_in : 0.f;
700 const float cos_h = r_rotated * inv_chroma_in;
701 const float sin_h = g_rotated * inv_chroma_in;
702 const float chroma_boost =
d->chroma_global + scalar_product(opacities, chroma);
703 const float vibrance =
d->vibrance * (1.0f - powf(chroma_in, fabsf(
d->vibrance)));
704 const float chroma_factor =
MAX(1.f + chroma_boost + vibrance, 0.f);
705 float chroma_out = chroma_in * chroma_factor;
708 const float r_shifted = chroma_out * cos_h + 0.21902143f;
709 const float g_shifted = chroma_out * sin_h + 0.54371398f;
712 const float r_limit = -0.21902143f / cos_h;
713 chroma_out =
MIN(r_limit, chroma_out);
717 const float g_limit = -0.54371398f / sin_h;
718 chroma_out =
MIN(g_limit, chroma_out);
720 if(r_shifted + g_shifted > 1.f)
722 const float sum_limit = (1.f - 0.21902143f - 0.54371398f) / (cos_h + sin_h);
723 chroma_out =
MIN(sum_limit, chroma_out);
725 Yrg_v[1] = chroma_out * cos_h + 0.21902143f;
726 Yrg_v[2] = chroma_out * sin_h + 0.54371398f;
729 dt_aligned_pixel_simd_t LMS_work_v = Yrg_to_LMS_simd(Yrg_v);
732 RGB_v = LMS_to_gradingRGB_simd(LMS_work_v);
736 const dt_aligned_pixel_simd_t slopes_v
737 = opacities_comp[2] * (opacities_comp[0] + opacities[0] * shadows_v) + opacities[2] * highlights_v;
743 const dt_aligned_pixel_simd_t RGB_abs_v = dt_simd_abs(RGB_v) /
d->white_fulcrum;
746 RGB_v = dt_simd_copysign(dt_simd_pow(RGB_abs_v, midtones_v) *
d->white_fulcrum, RGB_v);
750 LMS_work_v = gradingRGB_to_LMS_simd(RGB_v);
751 Yrg_v = LMS_to_Yrg_simd(LMS_work_v);
754 Yrg_v[0] = powf(
MAX(Yrg_v[0] /
d->white_fulcrum, 0.f),
d->midtones_Y) *
d->white_fulcrum;
757 Yrg_v[0] =
d->grey_fulcrum * powf(Yrg_v[0] /
d->grey_fulcrum,
d->contrast);
759 LMS_work_v = Yrg_to_LMS_simd(Yrg_v);
760 dt_aligned_pixel_simd_t XYZ_D65_v = LMS_to_XYZ_simd(LMS_work_v);
765 dt_aligned_pixel_simd_t Jab_v = dt_XYZ_2_JzAzBz_simd(XYZ_D65_v);
768 float JC[2] = { Jab_v[0], dt_fast_hypotf(Jab_v[1], Jab_v[2]) };
769 const float h = atan2f(Jab_v[2], Jab_v[1]);
770 const float inv_chroma = (JC[1] > 0.f) ? 1.f / JC[1] : 0.f;
771 const float cos_H = Jab_v[1] * inv_chroma;
772 const float sin_H = Jab_v[2] * inv_chroma;
777 const float T = atan2f(JC[1], JC[0]);
778 const float sin_T = sinf(T);
779 const float cos_T = cosf(T);
787 const float boosts[2] = { 1.f +
d->brilliance_global + scalar_product(opacities, brilliance),
788 d->saturation_global + scalar_product(opacities, saturation) };
790 SO[0] = JC[0] * M_rot_dir[0][0] + JC[1] * M_rot_dir[0][1];
792 SO[0] =
MAX(SO[0] * boosts[0], 0.f);
795 JC[0] =
MAX(SO[0] * M_rot_inv[0][0] + SO[1] * M_rot_inv[0][1], 0.f);
796 JC[1] =
MAX(SO[0] * M_rot_inv[1][0] + SO[1] * M_rot_inv[1][1], 0.f);
801 const float sat = (JC[0] > 0.f) ?
soft_clip(JC[1] / JC[0], 0.8f * out_max_sat_h, out_max_sat_h)
803 const float max_C_at_sat = JC[0] * sat;
805 const float max_J_at_sat = (sat > 0.f) ? JC[1] / sat : JC[0];
806 JC[0] = (JC[0] + max_J_at_sat) / 2.f;
807 JC[1] = (JC[1] + max_C_at_sat) / 2.f;
812 const float d0 = 1.6295499532821566e-11f;
813 const float dd = -0.56f;
814 float Iz = JC[0] +
d0;
815 Iz /= (1.f + dd - dd * Iz);
819 = { { 1.0f, 0.1386050432715393f, 0.0580473161561189f, 0.0f },
820 { 1.0f, -0.1386050432715393f, -0.0580473161561189f, 0.0f },
821 { 1.0f, -0.0960192420263190f, -0.8118918960560390f, 0.0f } };
824 const dt_aligned_pixel_simd_t IzAzBz_v = { Iz, JC[1] * cos_H, JC[1] * sin_H, 0.f };
825 const dt_aligned_pixel_simd_t LMS_test_v = dt_mat3x4_mul_vec4(IzAzBz_v, jz_ai0, jz_ai1, jz_ai2);
829 if(LMS_test_v[0] < 0.f)
830 max_C =
MIN(-Iz / (
AI[0][1] * cos_H +
AI[0][2] * sin_H), max_C);
832 if(LMS_test_v[1] < 0.f)
833 max_C =
MIN(-Iz / (
AI[1][1] * cos_H +
AI[1][2] * sin_H), max_C);
835 if(LMS_test_v[2] < 0.f)
836 max_C =
MIN(-Iz / (
AI[2][1] * cos_H +
AI[2][2] * sin_H), max_C);
839 const dt_aligned_pixel_simd_t Jab_out_v = { JC[0], max_C * cos_H, max_C * sin_H, 0.f };
840 XYZ_D65_v = dt_JzAzBz_2_XYZ_simd(Jab_out_v);
844 dt_aligned_pixel_simd_t xyY_v = dt_XYZ_to_xyY_simd(XYZ_D65_v);
845 dt_aligned_pixel_simd_t JCH_v = xyY_to_dt_UCS_JCH_simd(xyY_v, L_white);
846 dt_aligned_pixel_simd_t HCB_v = dt_UCS_JCH_to_HCB_simd(JCH_v);
848 const float radius = dt_fast_hypotf(HCB_v[1], HCB_v[2]);
849 const float sin_T = (radius > 0.f) ? HCB_v[1] / radius : 0.f;
850 const float cos_T = (radius > 0.f) ? HCB_v[2] / radius : 0.f;
851 const float DT_ALIGNED_PIXEL M_rot_inv[2][2] = { { cos_T, sin_T }, { -sin_T, cos_T } };
853 float P =
MAX(HCB_v[1], FLT_MIN);
854 float W = sin_T * HCB_v[1] + cos_T * HCB_v[2];
856 const dt_aligned_pixel_simd_t sat_bri_v = dt_simd_max_zero((dt_aligned_pixel_simd_t){
857 1.f +
d->saturation_global + scalar_product(opacities, saturation),
858 1.f +
d->brilliance_global + scalar_product(opacities, brilliance),
861 float a = sat_bri_v[0];
862 const float b = sat_bri_v[1];
864 const float max_a = dt_fast_hypotf(
P, W) /
P;
867 const float P_prime = (a - 1.f) *
P;
868 const float W_prime = sqrtf(sqf(
P) * (1.f - sqf(a)) + sqf(W)) * b;
870 HCB_v[1] =
MAX(M_rot_inv[0][0] * P_prime + M_rot_inv[0][1] * W_prime, 0.f);
871 HCB_v[2] =
MAX(M_rot_inv[1][0] * P_prime + M_rot_inv[1][1] * W_prime, 0.f);
873 JCH_v = dt_UCS_HCB_to_JCH_simd(HCB_v);
874 const float max_colorfulness =
lookup_gamut(gamut_LUT, JCH_v[2]);
875 const float max_chroma = 15.932993652962535f * powf(JCH_v[0] * L_white, 0.6523997524738018f)
876 * powf(max_colorfulness, 0.6007557017508491f) / L_white;
877 const dt_aligned_pixel_simd_t JCH_gamut_boundary_v = { JCH_v[0], max_chroma, JCH_v[2], 0.f };
878 const dt_aligned_pixel_simd_t HSB_gamut_boundary_v = dt_UCS_JCH_to_HSB_simd(JCH_gamut_boundary_v);
879 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 };
880 HSB_v[1] =
soft_clip(HSB_v[1], 0.8f * HSB_gamut_boundary_v[1], HSB_gamut_boundary_v[1]);
881 JCH_v = dt_UCS_HSB_to_JCH_simd(HSB_v);
882 xyY_v = dt_UCS_JCH_to_xyY_simd(JCH_v, L_white);
883 XYZ_D65_v = dt_xyY_to_XYZ_simd(xyY_v);
886 dt_aligned_pixel_simd_t pix_out_v = dt_mat3x4_mul_vec4(XYZ_D65_v, output0, output1, output2);
889 const size_t i = idx / out_width;
890 const size_t j = idx -
i * out_width;
892 dt_aligned_pixel_simd_t color_v;
893 if(
i % checker_1 <
i % checker_2)
895 if(j % checker_1 < j % checker_2) color_v = checker_color_2_v;
896 else color_v = checker_color_1_v;
900 if(j % checker_1 < j % checker_2) color_v = checker_color_1_v;
901 else color_v = checker_color_2_v;
904 const float opacity = opacities[
d->mask_type];
905 const float opacity_comp = 1.0f - opacity;
907 dt_aligned_pixel_simd_t image_v = dt_simd_max_zero(pix_out_v);
908 if(
d->mask_preview_black_and_white)
910 const float gray = 0.3f * image_v[0] + 0.59f * image_v[1] + 0.11f * image_v[2];
911 image_v[0] = image_v[1] = image_v[2] = gray;
913 pix_out_v = opacity_comp * color_v + opacity * image_v;
918 pix_out_v = dt_simd_max_zero(pix_out_v);
919 pix_out_v[3] = pix_in_v[3];
921 dt_store_simd_nontemporal(pix_out, pix_out_v);
938 const int devid = pipe->
devid;
949 cl_mem dev_profile_info = NULL;
950 cl_mem dev_profile_lut = NULL;
952 cl_float *profile_lut_cl = NULL;
954 cl_mem input_matrix_cl = NULL;
955 cl_mem output_matrix_cl = NULL;
956 cl_mem gamut_LUT = NULL;
959 &dev_profile_info, &dev_profile_lut);
960 if(err != CL_SUCCESS)
goto error;
997 float input_matrix_3x4[12];
998 float output_matrix_3x4[12];
1008 const int mask_display =
d->mask_display;
1011 const int checker_2 = 2 * checker_1;
1012 const int mask_type =
d->mask_type;
1015 const cl_float2 hue_rotation_row_0 = {{ cosf(
d->hue_angle), -sinf(
d->hue_angle) }};
1016 const cl_float2 hue_rotation_row_1 = {{ sinf(
d->hue_angle), cosf(
d->hue_angle) }};
1057 if(err != CL_SUCCESS)
goto error;
1077 const int program = 8;
1095static inline float Delta_H(
const float h_1,
const float h_2)
1099 float diff = h_1 - h_2;
1115 d->checker_color_1[0] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker1/red"), 0.f, 1.f);
1116 d->checker_color_1[1] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker1/green"), 0.f, 1.f);
1117 d->checker_color_1[2] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker1/blue"), 0.f, 1.f);
1119 d->checker_color_2[0] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker2/red"), 0.f, 1.f);
1120 d->checker_color_2[1] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker2/green"), 0.f, 1.f);
1121 d->checker_color_2[2] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker2/blue"), 0.f, 1.f);
1122 d->checker_color_2[3] = 1.f;
1123 d->checker_size =
MAX(
dt_conf_get_int(
"plugins/darkroom/colorbalancergb/checker/size"), 2);
1124 d->mask_preview_black_and_white
1125 =
dt_conf_get_bool(
"plugins/darkroom/colorbalancergb/mask_preview/greyscaled");
1128 d->checker_color_1[3] =
d->mask_preview_black_and_white;
1135 d->vibrance =
p->vibrance;
1136 d->contrast = 1.0f +
p->contrast;
1137 d->grey_fulcrum =
p->grey_fulcrum;
1139 d->chroma_global =
p->chroma_global;
1140 d->chroma[0] =
p->chroma_shadows;
1141 d->chroma[1] =
p->chroma_midtones;
1142 d->chroma[2] =
p->chroma_highlights;
1145 d->saturation_global =
p->saturation_global;
1146 d->saturation[0] =
p->saturation_shadows;
1147 d->saturation[1] =
p->saturation_midtones;
1148 d->saturation[2] =
p->saturation_highlights;
1149 d->saturation[3] = 0.f;
1151 d->brilliance_global =
p->brilliance_global;
1152 d->brilliance[0] =
p->brilliance_shadows;
1153 d->brilliance[1] =
p->brilliance_midtones;
1154 d->brilliance[2] =
p->brilliance_highlights;
1155 d->brilliance[3] = 0.f;
1157 d->hue_angle =
M_PI *
p->hue_angle / 180.f;
1162 Ych_to_gradingRGB(Ych_norm, RGB_norm);
1167 Ych_to_gradingRGB(Ych,
d->global);
1168 for(
size_t c = 0; c < 3; c++)
d->global[c] = (
d->global[c] - RGB_norm[c]) + RGB_norm[c] *
p->global_Y;
1174 Ych_to_gradingRGB(Ych,
d->shadows);
1175 for(
size_t c = 0; c < 3; c++)
d->shadows[c] = 1.f + (
d->shadows[c] - RGB_norm[c]) +
p->shadows_Y;
1176 d->shadows_weight = 2.f +
p->shadows_weight * 2.f;
1182 Ych_to_gradingRGB(Ych,
d->highlights);
1183 for(
size_t c = 0; c < 3; c++)
d->highlights[c] = 1.f + (
d->highlights[c] - RGB_norm[c]) +
p->highlights_Y;
1184 d->highlights_weight = 2.f +
p->highlights_weight * 2.f;
1190 Ych_to_gradingRGB(Ych,
d->midtones);
1191 for(
size_t c = 0; c < 3; c++)
d->midtones[c] = 1.f / (1.f + (
d->midtones[c] - RGB_norm[c]));
1192 d->midtones_Y = 1.f / (1.f +
p->midtones_Y);
1193 d->white_fulcrum = exp2f(
p->white_fulcrum);
1194 d->midtones_weight = sqf(
d->shadows_weight) * sqf(
d->highlights_weight) /
1195 (sqf(
d->shadows_weight) + sqf(
d->highlights_weight));
1196 d->mask_grey_fulcrum = powf(
p->mask_grey_fulcrum, 0.4101205819200422f);
1199 if(
p->saturation_formula !=
d->saturation_formula)
d->lut_inited =
FALSE;
1200 d->saturation_formula =
p->saturation_formula;
1207 if(work_profile !=
d->work_profile)
1210 d->work_profile = work_profile;
1221 for(
size_t k = 0;
k <
LUT_ELEM;
k++) LUT_saturation[
k] = 0.f;
1234 for(
size_t b = 0; b <
STEPS; b++)
1237 (float)b / (
float)(
STEPS - 1), 0.f };
1239 float saturation = 0.f;
1242 dot_product(
rgb, input_matrix,
XYZ);
1245 dt_XYZ_2_JzAzBz(
XYZ, Jab);
1248 Jch[1] = dt_fast_hypotf(Jab[2], Jab[1]);
1249 Jch[2] = atan2f(Jab[2], Jab[1]);
1251 saturation = (Jch[0] > 0.f) ? Jch[1] / Jch[0] : 0.f;
1255 LUT_saturation[index] = fmaxf(saturation, LUT_saturation[index]);
1260 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;
1263 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;
1264 d->gamut_LUT[1] = (LUT_saturation[
LUT_ELEM - 1] + LUT_saturation[0] + LUT_saturation[1] + LUT_saturation[2] + LUT_saturation[3]) / 5.f;
1265 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;
1270 dt_aligned_pixel_t D65_xyY = { 0.31269999999999992f, 0.32899999999999996f , 1.f, 0.f };
1278 dot_product(RGB_red, input_matrix, XYZ_red);
1279 dot_product(RGB_green, input_matrix, XYZ_green);
1280 dot_product(RGB_blue, input_matrix, XYZ_blue);
1288 const float h_red = atan2f(xyY_red[1] - D65_xyY[1], xyY_red[0] - D65_xyY[0]);
1289 const float h_green = atan2f(xyY_green[1] - D65_xyY[1], xyY_green[0] - D65_xyY[0]);
1290 const float h_blue = atan2f(xyY_blue[1] - D65_xyY[1], xyY_blue[0] - D65_xyY[0]);
1292 float *
const restrict dt_UCS_LUT =
d->gamut_LUT;
1296 for(
int i = 0;
i < 50 * 360;
i++)
1298 const float angle = -
M_PI_F + ((float)
i) / (50.f * 360.f) * 2.f *
M_PI_F;
1299 const float tan_angle = tanf(angle);
1301 const float t_1 =
Delta_H(angle, h_blue) /
Delta_H(h_red, h_blue);
1302 const float t_2 =
Delta_H(angle, h_red) /
Delta_H(h_green, h_red);
1303 const float t_3 =
Delta_H(angle, h_green) /
Delta_H(h_blue, h_green);
1308 if(t_1 == CLAMP(t_1, 0, 1))
1310 const float t = (D65_xyY[1] - xyY_blue[1] + tan_angle * (xyY_blue[0] - D65_xyY[0]))
1311 / (xyY_red[1] - xyY_blue[1] + tan_angle * (xyY_blue[0] - xyY_red[0]));
1312 x_t = xyY_blue[0] +
t * (xyY_red[0] - xyY_blue[0]);
1313 y_t = xyY_blue[1] +
t * (xyY_red[1] - xyY_blue[1]);
1315 else if(t_2 == CLAMP(t_2, 0, 1))
1317 const float t = (D65_xyY[1] - xyY_red[1] + tan_angle * (xyY_red[0] - D65_xyY[0]))
1318 / (xyY_green[1] - xyY_red[1] + tan_angle * (xyY_red[0] - xyY_green[0]));
1319 x_t = xyY_red[0] +
t * (xyY_green[0] - xyY_red[0]);
1320 y_t = xyY_red[1] +
t * (xyY_green[1] - xyY_red[1]);
1322 else if(t_3 == CLAMP(t_3, 0, 1))
1324 const float t = (D65_xyY[1] - xyY_green[1] + tan_angle * (xyY_green[0] - D65_xyY[0]))
1325 / (xyY_blue[1] - xyY_green[1] + tan_angle * (xyY_green[0] - xyY_blue[0]));
1326 x_t = xyY_green[0] +
t * (xyY_blue[0] - xyY_green[0]);
1327 y_t = xyY_green[1] +
t * (xyY_blue[1] - xyY_green[1]);
1332 float UV_star_prime[2];
1336 const float H = atan2f(UV_star_prime[1], UV_star_prime[0]) * 180.f /
M_PI_F;
1337 const float H_round = roundf(
H);
1338 if(fabsf(
H - H_round) < 0.02f)
1340 int index = (int)(H_round + 180);
1341 index += (index < 0) ? 360 : 0;
1342 index -= (index > 359) ? 360 : 0;
1344 dt_UCS_LUT[index] = UV_star_prime[0] * UV_star_prime[0] + UV_star_prime[1] * UV_star_prime[1];
1350 d->lut_inited =
TRUE;
1375 d->gamut_LUT = NULL;
1390 work_profile->unbounded_coeffs_in, work_profile->
lutsize,
1396 Ych[2] = 2.f *
M_PI + Ych[2];
1410 hue = (hue > 360.f) ? hue - 360.f : hue;
1413 if(picker ==
g->global_H)
1416 p->global_C = Ych[1] * Ych[0];
1420 else if(picker ==
g->shadows_H)
1423 p->shadows_C = Ych[1] * Ych[0];
1427 else if(picker ==
g->midtones_H)
1429 p->midtones_H = hue;
1430 p->midtones_C = Ych[1] * Ych[0];
1434 else if(picker ==
g->highlights_H)
1436 p->highlights_H = hue;
1437 p->highlights_C = Ych[1] * Ych[0];
1441 else if(picker ==
g->white_fulcrum)
1443 p->white_fulcrum = log2f(max_Ych[0]);
1446 else if(picker ==
g->grey_fulcrum)
1448 p->grey_fulcrum = Ych[0];
1452 fprintf(stderr,
"[colorbalancergb] unknown color picker\n");
1467 const float *
const restrict in = (
const float *)
i;
1471 for(
size_t k = 0;
k < (size_t)roi_out->
width * roi_out->
height * 4;
k += 4)
1475 if(isfinite(Ych[0]))
1476 max_Y = fmaxf(max_Y, Ych[0]);
1479 p->white_fulcrum = log2f(fmaxf(max_Y, 1e-6f));
1485 const float x_min = 0;
1486 const float x_max = 1;
1487 const float x_range = x_max - x_min;
1493 const float x = x_min + stop * x_range;
1499 Ych_to_XYZ(Ych,
XYZ);
1500 dt_XYZ_to_Rec709_D65(
XYZ,
RGB);
1501 const float max_RGB = fmaxf(fmaxf(
RGB[0],
RGB[1]),
RGB[2]);
1502 for(
size_t c = 0; c < 3; c++)
RGB[c] = powf(
RGB[c] / max_RGB, 1.f / 2.2f);
1506 gtk_widget_queue_draw(w);
1515 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->
gui->
off),
TRUE);
1523 g->mask_display = !
g->mask_display;
1527 if(togglebutton ==
g->shadows_weight)
g->mask_type =
MASK_SHADOWS;
1528 if(togglebutton ==
g->mask_grey_fulcrum)
g->mask_type =
MASK_MIDTONES;
1550 const float shadows_weight = 2.f +
p->shadows_weight * 2.f;
1551 const float highlights_weight = 2.f +
p->highlights_weight * 2.f;
1554 GtkAllocation allocation;
1555 gtk_widget_get_allocation(widget, &allocation);
1556 GtkStyleContext *context = gtk_widget_get_style_context(widget);
1558 cairo_surface_t *cst =
1560 PangoFontDescription *desc =
1562 cairo_t *cr = cairo_create(cst);
1563 PangoLayout *layout = pango_cairo_create_layout(cr);
1565 const gint font_size = pango_font_description_get_size(desc);
1566 pango_font_description_set_size(desc, 0.95 * font_size);
1567 pango_layout_set_font_description(layout, desc);
1574 snprintf(text,
sizeof(text),
"X");
1575 pango_layout_set_text(layout, text, -1);
1576 pango_layout_get_pixel_extents(layout, &ink, NULL);
1577 const float line_height = ink.height;
1580 const float margin_top = inset;
1581 const float margin_bottom = line_height + 2 * inset;
1582 const float margin_left = line_height + inset;
1583 const float margin_right = 0;
1585 const float graph_width = allocation.width - margin_right - margin_left;
1586 const float graph_height = allocation.height - margin_bottom - margin_top;
1588 gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);
1591 cairo_pattern_t *grad;
1592 grad = cairo_pattern_create_linear(margin_left, 0.0, graph_width, 0.0);
1594 cairo_set_line_width(cr, 0.0);
1595 cairo_rectangle(cr, margin_left, graph_height + 2 * inset, graph_width, line_height);
1596 cairo_set_source(cr, grad);
1598 cairo_pattern_destroy(grad);
1601 const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, line_height);
1602 unsigned char *data = malloc(stride * graph_height);
1603 cairo_surface_t *surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, (
size_t)line_height, (
size_t)graph_height, stride);
1606 const size_t checker_2 = 2 * checker_1;
1608 for(
size_t i = 0;
i < (size_t)graph_height;
i++)
1609 for(
size_t j = 0; j < (size_t)line_height; j++)
1611 const size_t k = ((
i * (size_t)line_height) + j) * 4;
1612 unsigned char color;
1613 const float alpha = (float)
i / graph_height;
1614 if(
i % checker_1 <
i % checker_2)
1616 if(j % checker_1 < j % checker_2)
color = 150;
1621 if(j % checker_1 < j % checker_2)
color = 100;
1625 for(
size_t c = 0; c < 4; ++c) data[
k + c] =
color * alpha;
1626 data[
k+3] = alpha * 255;
1629 cairo_set_source_surface(cr, surface, 0, margin_top);
1632 cairo_surface_destroy(surface);
1635 cairo_translate(cr, margin_left, margin_top);
1636 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
1639 cairo_rectangle(cr, 0, 0, graph_width, graph_height);
1640 cairo_fill_preserve(cr);
1644 const float midtones_weight
1645 = sqf(shadows_weight) * sqf(highlights_weight) / (sqf(shadows_weight) + sqf(highlights_weight));
1646 const float mask_grey_fulcrum = powf(
p->mask_grey_fulcrum, 0.4101205819200422f);
1653 const float Y =
k / (float)(
LUT_ELEM - 1);
1655 opacity_masks(Y, shadows_weight, highlights_weight, midtones_weight, mask_grey_fulcrum, output, NULL);
1656 for(
size_t c = 0; c < 3; c++) LUT[c][
k] = output[c];
1662 for(
size_t c = 0; c < 3; c++)
1664 GdkRGBA line_color = { fg_color.red * (1. - (2 - c) / 4.),
1665 fg_color.green * (1. - (2 - c) / 4.),
1666 fg_color.blue * (1. - (2 - c) / 4.),
1670 cairo_move_to(cr, 0, (1.f - LUT[c][0]) * graph_height);
1673 const float x = (float)
k / (
float)(
LUT_ELEM - 1) * graph_width;
1674 const float y = (1.f - LUT[c][
k]) * graph_height;
1675 cairo_line_to(cr,
x, y);
1685 pango_font_description_set_size(desc, font_size);
1686 pango_layout_set_font_description(layout, desc);
1689 cairo_set_source_surface(crf, cst, 0, 0);
1691 cairo_surface_destroy(cst);
1692 g_object_unref(layout);
1693 pango_font_description_free(desc);
1717 if(
IS_NULL_PTR(w) || w ==
g->shadows_weight || w ==
g->highlights_weight || w ==
g->mask_grey_fulcrum)
1718 gtk_widget_queue_draw(GTK_WIDGET(
g->area));
1811 gtk_widget_set_tooltip_text(
g->hue_angle, _(
"rotate all hues by an angle, at the same luminance"));
1817 gtk_widget_set_tooltip_text(
g->vibrance, _(
"increase colorfulness mostly on low-chroma colors"));
1823 gtk_widget_set_tooltip_text(
g->contrast, _(
"increase the contrast at constant chromaticity"));
1831 gtk_widget_set_tooltip_text(
g->chroma_global, _(
"increase colorfulness at same luminance globally"));
1836 gtk_widget_set_tooltip_text(
g->chroma_shadows, _(
"increase colorfulness at same luminance mostly in shadows"));
1841 gtk_widget_set_tooltip_text(
g->chroma_midtones, _(
"increase colorfulness at same luminance mostly in mid-tones"));
1846 gtk_widget_set_tooltip_text(
g->chroma_highlights, _(
"increase colorfulness at same luminance mostly in highlights"));
1853 gtk_widget_set_tooltip_text(
g->saturation_global, _(
"add or remove saturation by an absolute amount"));
1858 gtk_widget_set_tooltip_text(
g->saturation_shadows, _(
"increase or decrease saturation proportionally to the original pixel saturation"));
1863 gtk_widget_set_tooltip_text(
g->saturation_midtones, _(
"increase or decrease saturation proportionally to the original pixel saturation"));
1868 gtk_widget_set_tooltip_text(
g->saturation_highlights, _(
"increase or decrease saturation proportionally to the original pixel saturation"));
1875 gtk_widget_set_tooltip_text(
g->brilliance_global, _(
"add or remove brilliance by an absolute amount"));
1880 gtk_widget_set_tooltip_text(
g->brilliance_shadows, _(
"increase or decrease brilliance proportionally to the original pixel brilliance"));
1885 gtk_widget_set_tooltip_text(
g->brilliance_midtones, _(
"increase or decrease brilliance proportionally to the original pixel brilliance"));
1890 gtk_widget_set_tooltip_text(
g->brilliance_highlights, _(
"increase or decrease brilliance proportionally to the original pixel brilliance"));
1901 gtk_widget_set_tooltip_text(
g->global_Y, _(
"global luminance offset"));
1906 gtk_widget_set_tooltip_text(
g->global_H, _(
"hue of the global color offset"));
1912 gtk_widget_set_tooltip_text(
g->global_C, _(
"chroma of the global color offset"));
1920 gtk_widget_set_tooltip_text(
g->shadows_Y, _(
"luminance gain in shadows"));
1925 gtk_widget_set_tooltip_text(
g->shadows_H, _(
"hue of the color gain in shadows"));
1931 gtk_widget_set_tooltip_text(
g->shadows_C, _(
"chroma of the color gain in shadows"));
1939 gtk_widget_set_tooltip_text(
g->highlights_Y, _(
"luminance gain in highlights"));
1944 gtk_widget_set_tooltip_text(
g->highlights_H, _(
"hue of the color gain in highlights"));
1950 gtk_widget_set_tooltip_text(
g->highlights_C, _(
"chroma of the color gain in highlights"));
1958 gtk_widget_set_tooltip_text(
g->midtones_Y, _(
"luminance exponent in mid-tones"));
1963 gtk_widget_set_tooltip_text(
g->midtones_H, _(
"hue of the color exponent in mid-tones"));
1969 gtk_widget_set_tooltip_text(
g->midtones_C, _(
"chroma of the color exponent in mid-tones"));
1975 gtk_widget_set_tooltip_text(
g->saturation_formula, _(
"choose in which uniform color space the saturation is computed."));
1979 g->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
1980 gtk_widget_set_hexpand(GTK_WIDGET(
g->area),
TRUE);
1981 g_object_set_data(G_OBJECT(
g->area),
"iop-instance", self);
1983 gtk_box_pack_start(GTK_BOX(self->
gui->
widget),
1985 "plugins/darkroom/colorbalancergb/graphheight", 200, 100),
1993 gtk_widget_set_tooltip_text(
g->shadows_weight, _(
"weight of the shadows over the whole tonal range"));
1996 g_signal_connect(G_OBJECT(
g->shadows_weight),
"quad-pressed", G_CALLBACK(
mask_callback), self);
2001 gtk_widget_set_tooltip_text(
g->mask_grey_fulcrum, _(
"position of the middle-gray reference for masking"));
2004 g_signal_connect(G_OBJECT(
g->mask_grey_fulcrum),
"quad-pressed", G_CALLBACK(
mask_callback), self);
2009 gtk_widget_set_tooltip_text(
g->highlights_weight, _(
"weights of highlights over the whole tonal range"));
2012 g_signal_connect(G_OBJECT(
g->highlights_weight),
"quad-pressed", G_CALLBACK(
mask_callback), self);
2019 gtk_widget_set_tooltip_text(
g->white_fulcrum, _(
"peak white luminance value used to normalize the power function"));
2025 gtk_widget_set_tooltip_text(
g->grey_fulcrum, _(
"peak gray luminance value used to normalize the power function"));
2061 Ych_to_XYZ(Ych,
XYZ);
2062 dt_XYZ_to_Rec709_D65(
XYZ,
RGB);
2063 const float max_RGB = fmaxf(fmaxf(
RGB[0],
RGB[1]),
RGB[2]);
2064 for(
size_t c = 0; c < 3; c++)
RGB[c] = powf(
RGB[c] / max_RGB, 1.f / 2.2f);
2070 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)
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_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
dt_iop_buffer_type_t datatype
int kernel_colorbalance_rgb
struct dt_iop_order_iccprofile_info_t * work_profile
gboolean mask_preview_black_and_white
dt_iop_colorbalancrgb_saturation_t saturation_formula
dt_iop_colorbalancergb_mask_data_t mask_type
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__