624 const float *
const restrict in = __builtin_assume_aligned(((
const float *
const restrict)ivoid), 64);
625 float *
const restrict
out = __builtin_assume_aligned(((
float *
const restrict)
ovoid), 64);
626 const float *
const restrict gamut_LUT = __builtin_assume_aligned(((
const float *
const restrict)
d->gamut_LUT), 64);
628 const float *
const restrict global = __builtin_assume_aligned((
const float *
const restrict)
d->global, 16);
629 const float *
const restrict highlights = __builtin_assume_aligned((
const float *
const restrict)
d->highlights, 16);
630 const float *
const restrict shadows = __builtin_assume_aligned((
const float *
const restrict)
d->shadows, 16);
631 const float *
const restrict midtones = __builtin_assume_aligned((
const float *
const restrict)
d->midtones, 16);
633 const float *
const restrict chroma = __builtin_assume_aligned((
const float *
const restrict)
d->chroma, 16);
634 const float *
const restrict saturation = __builtin_assume_aligned((
const float *
const restrict)
d->saturation, 16);
635 const float *
const restrict brilliance = __builtin_assume_aligned((
const float *
const restrict)
d->brilliance, 16);
637 const dt_aligned_pixel_simd_t input0 = dt_colormatrix_row_to_simd(input_matrix_transposed, 0);
638 const dt_aligned_pixel_simd_t input1 = dt_colormatrix_row_to_simd(input_matrix_transposed, 1);
639 const dt_aligned_pixel_simd_t input2 = dt_colormatrix_row_to_simd(input_matrix_transposed, 2);
640 const dt_aligned_pixel_simd_t output0 = dt_colormatrix_row_to_simd(output_matrix_transposed, 0);
641 const dt_aligned_pixel_simd_t output1 = dt_colormatrix_row_to_simd(output_matrix_transposed, 1);
642 const dt_aligned_pixel_simd_t output2 = dt_colormatrix_row_to_simd(output_matrix_transposed, 2);
644 const dt_aligned_pixel_simd_t global_v = dt_load_simd_aligned(global);
645 const dt_aligned_pixel_simd_t highlights_v = dt_load_simd_aligned(highlights);
646 const dt_aligned_pixel_simd_t shadows_v = dt_load_simd_aligned(shadows);
647 const dt_aligned_pixel_simd_t midtones_v = dt_load_simd_aligned(midtones);
648 const dt_aligned_pixel_simd_t jz_ai0 = dt_colormatrix_row_to_simd(AI_transposed, 0);
649 const dt_aligned_pixel_simd_t jz_ai1 = dt_colormatrix_row_to_simd(AI_transposed, 1);
650 const dt_aligned_pixel_simd_t jz_ai2 = dt_colormatrix_row_to_simd(AI_transposed, 2);
652 const gboolean mask_display =
d->mask_display;
654 const dt_aligned_pixel_simd_t checker_color_1_v = dt_load_simd(
d->checker_color_1);
655 const dt_aligned_pixel_simd_t checker_color_2_v = dt_load_simd(
d->checker_color_2);
656 const size_t checker_1
658 const size_t checker_2 = 2 * checker_1;
659 const size_t npixels = (size_t)roi_out->
width * roi_out->
height;
660 const size_t out_width = roi_out->
width;
664 { cosf(
d->hue_angle), -sinf(
d->hue_angle) },
665 { sinf(
d->hue_angle), cosf(
d->hue_angle) },
668 for(
size_t idx = 0; idx < npixels; idx++)
670 const size_t k = idx * 4;
671 const float *
const restrict pix_in = __builtin_assume_aligned(in +
k, 16);
672 float *
const restrict pix_out = __builtin_assume_aligned(
out +
k, 16);
673 const dt_aligned_pixel_simd_t pix_in_v = dt_load_simd_aligned(pix_in);
675 dt_aligned_pixel_simd_t RGB_v = dt_simd_max_zero(pix_in_v);
677 const dt_aligned_pixel_simd_t LMS_v = dt_mat3x4_mul_vec4(RGB_v, input0, input1, input2);
678 dt_aligned_pixel_simd_t Yrg_v = LMS_to_Yrg_simd(LMS_v);
679 Yrg_v[0] =
MAX(Yrg_v[0], 0.f);
682 opacity_masks(powf(Yrg_v[0], 0.4101205819200422f),
d->shadows_weight,
d->highlights_weight,
683 d->midtones_weight,
d->mask_grey_fulcrum, opacities, opacities_comp);
687 const float r_centered = Yrg_v[1] - 0.21902143f;
688 const float g_centered = Yrg_v[2] - 0.54371398f;
689 const float r_rotated = hue_rotation_matrix[0][0] * r_centered + hue_rotation_matrix[0][1] * g_centered;
690 const float g_rotated = hue_rotation_matrix[1][0] * r_centered + hue_rotation_matrix[1][1] * g_centered;
691 const float chroma_in = dt_fast_hypotf(g_rotated, r_rotated);
692 const float inv_chroma_in = (chroma_in > 0.f) ? 1.f / chroma_in : 0.f;
693 const float cos_h = r_rotated * inv_chroma_in;
694 const float sin_h = g_rotated * inv_chroma_in;
695 const float chroma_boost =
d->chroma_global + scalar_product(opacities, chroma);
696 const float vibrance =
d->vibrance * (1.0f - powf(chroma_in, fabsf(
d->vibrance)));
697 const float chroma_factor =
MAX(1.f + chroma_boost + vibrance, 0.f);
698 float chroma_out = chroma_in * chroma_factor;
701 const float r_shifted = chroma_out * cos_h + 0.21902143f;
702 const float g_shifted = chroma_out * sin_h + 0.54371398f;
705 const float r_limit = -0.21902143f / cos_h;
706 chroma_out =
MIN(r_limit, chroma_out);
710 const float g_limit = -0.54371398f / sin_h;
711 chroma_out =
MIN(g_limit, chroma_out);
713 if(r_shifted + g_shifted > 1.f)
715 const float sum_limit = (1.f - 0.21902143f - 0.54371398f) / (cos_h + sin_h);
716 chroma_out =
MIN(sum_limit, chroma_out);
718 Yrg_v[1] = chroma_out * cos_h + 0.21902143f;
719 Yrg_v[2] = chroma_out * sin_h + 0.54371398f;
722 dt_aligned_pixel_simd_t LMS_work_v = Yrg_to_LMS_simd(Yrg_v);
725 RGB_v = LMS_to_gradingRGB_simd(LMS_work_v);
729 const dt_aligned_pixel_simd_t slopes_v
730 = opacities_comp[2] * (opacities_comp[0] + opacities[0] * shadows_v) + opacities[2] * highlights_v;
736 const dt_aligned_pixel_simd_t RGB_abs_v = dt_simd_abs(RGB_v) /
d->white_fulcrum;
739 RGB_v = dt_simd_copysign(dt_simd_pow(RGB_abs_v, midtones_v) *
d->white_fulcrum, RGB_v);
743 LMS_work_v = gradingRGB_to_LMS_simd(RGB_v);
744 Yrg_v = LMS_to_Yrg_simd(LMS_work_v);
747 Yrg_v[0] = powf(
MAX(Yrg_v[0] /
d->white_fulcrum, 0.f),
d->midtones_Y) *
d->white_fulcrum;
750 Yrg_v[0] =
d->grey_fulcrum * powf(Yrg_v[0] /
d->grey_fulcrum,
d->contrast);
752 LMS_work_v = Yrg_to_LMS_simd(Yrg_v);
753 dt_aligned_pixel_simd_t XYZ_D65_v = LMS_to_XYZ_simd(LMS_work_v);
758 dt_aligned_pixel_simd_t Jab_v = dt_XYZ_2_JzAzBz_simd(XYZ_D65_v);
761 float JC[2] = { Jab_v[0], dt_fast_hypotf(Jab_v[1], Jab_v[2]) };
762 const float h = atan2f(Jab_v[2], Jab_v[1]);
763 const float inv_chroma = (JC[1] > 0.f) ? 1.f / JC[1] : 0.f;
764 const float cos_H = Jab_v[1] * inv_chroma;
765 const float sin_H = Jab_v[2] * inv_chroma;
770 const float T = atan2f(JC[1], JC[0]);
771 const float sin_T = sinf(T);
772 const float cos_T = cosf(T);
780 const float boosts[2] = { 1.f +
d->brilliance_global + scalar_product(opacities, brilliance),
781 d->saturation_global + scalar_product(opacities, saturation) };
783 SO[0] = JC[0] * M_rot_dir[0][0] + JC[1] * M_rot_dir[0][1];
785 SO[0] =
MAX(SO[0] * boosts[0], 0.f);
788 JC[0] =
MAX(SO[0] * M_rot_inv[0][0] + SO[1] * M_rot_inv[0][1], 0.f);
789 JC[1] =
MAX(SO[0] * M_rot_inv[1][0] + SO[1] * M_rot_inv[1][1], 0.f);
794 const float sat = (JC[0] > 0.f) ?
soft_clip(JC[1] / JC[0], 0.8f * out_max_sat_h, out_max_sat_h)
796 const float max_C_at_sat = JC[0] * sat;
798 const float max_J_at_sat = (sat > 0.f) ? JC[1] / sat : JC[0];
799 JC[0] = (JC[0] + max_J_at_sat) / 2.f;
800 JC[1] = (JC[1] + max_C_at_sat) / 2.f;
805 const float d0 = 1.6295499532821566e-11f;
806 const float dd = -0.56f;
807 float Iz = JC[0] +
d0;
808 Iz /= (1.f + dd - dd * Iz);
812 = { { 1.0f, 0.1386050432715393f, 0.0580473161561189f, 0.0f },
813 { 1.0f, -0.1386050432715393f, -0.0580473161561189f, 0.0f },
814 { 1.0f, -0.0960192420263190f, -0.8118918960560390f, 0.0f } };
817 const dt_aligned_pixel_simd_t IzAzBz_v = { Iz, JC[1] * cos_H, JC[1] * sin_H, 0.f };
818 const dt_aligned_pixel_simd_t LMS_test_v = dt_mat3x4_mul_vec4(IzAzBz_v, jz_ai0, jz_ai1, jz_ai2);
822 if(LMS_test_v[0] < 0.f)
823 max_C =
MIN(-Iz / (
AI[0][1] * cos_H +
AI[0][2] * sin_H), max_C);
825 if(LMS_test_v[1] < 0.f)
826 max_C =
MIN(-Iz / (
AI[1][1] * cos_H +
AI[1][2] * sin_H), max_C);
828 if(LMS_test_v[2] < 0.f)
829 max_C =
MIN(-Iz / (
AI[2][1] * cos_H +
AI[2][2] * sin_H), max_C);
832 const dt_aligned_pixel_simd_t Jab_out_v = { JC[0], max_C * cos_H, max_C * sin_H, 0.f };
833 XYZ_D65_v = dt_JzAzBz_2_XYZ_simd(Jab_out_v);
837 dt_aligned_pixel_simd_t xyY_v = dt_XYZ_to_xyY_simd(XYZ_D65_v);
838 dt_aligned_pixel_simd_t JCH_v = xyY_to_dt_UCS_JCH_simd(xyY_v, L_white);
839 dt_aligned_pixel_simd_t HCB_v = dt_UCS_JCH_to_HCB_simd(JCH_v);
841 const float radius = dt_fast_hypotf(HCB_v[1], HCB_v[2]);
842 const float sin_T = (radius > 0.f) ? HCB_v[1] / radius : 0.f;
843 const float cos_T = (radius > 0.f) ? HCB_v[2] / radius : 0.f;
844 const float DT_ALIGNED_PIXEL M_rot_inv[2][2] = { { cos_T, sin_T }, { -sin_T, cos_T } };
846 float P =
MAX(HCB_v[1], FLT_MIN);
847 float W = sin_T * HCB_v[1] + cos_T * HCB_v[2];
849 const dt_aligned_pixel_simd_t sat_bri_v = dt_simd_max_zero((dt_aligned_pixel_simd_t){
850 1.f +
d->saturation_global + scalar_product(opacities, saturation),
851 1.f +
d->brilliance_global + scalar_product(opacities, brilliance),
854 float a = sat_bri_v[0];
855 const float b = sat_bri_v[1];
857 const float max_a = dt_fast_hypotf(
P, W) /
P;
860 const float P_prime = (a - 1.f) *
P;
861 const float W_prime = sqrtf(sqf(
P) * (1.f - sqf(a)) + sqf(W)) * b;
863 HCB_v[1] =
MAX(M_rot_inv[0][0] * P_prime + M_rot_inv[0][1] * W_prime, 0.f);
864 HCB_v[2] =
MAX(M_rot_inv[1][0] * P_prime + M_rot_inv[1][1] * W_prime, 0.f);
866 JCH_v = dt_UCS_HCB_to_JCH_simd(HCB_v);
867 const float max_colorfulness =
lookup_gamut(gamut_LUT, JCH_v[2]);
868 const float max_chroma = 15.932993652962535f * powf(JCH_v[0] * L_white, 0.6523997524738018f)
869 * powf(max_colorfulness, 0.6007557017508491f) / L_white;
870 const dt_aligned_pixel_simd_t JCH_gamut_boundary_v = { JCH_v[0], max_chroma, JCH_v[2], 0.f };
871 const dt_aligned_pixel_simd_t HSB_gamut_boundary_v = dt_UCS_JCH_to_HSB_simd(JCH_gamut_boundary_v);
872 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 };
873 HSB_v[1] =
soft_clip(HSB_v[1], 0.8f * HSB_gamut_boundary_v[1], HSB_gamut_boundary_v[1]);
874 JCH_v = dt_UCS_HSB_to_JCH_simd(HSB_v);
875 xyY_v = dt_UCS_JCH_to_xyY_simd(JCH_v, L_white);
876 XYZ_D65_v = dt_xyY_to_XYZ_simd(xyY_v);
879 dt_aligned_pixel_simd_t pix_out_v = dt_mat3x4_mul_vec4(XYZ_D65_v, output0, output1, output2);
882 const size_t i = idx / out_width;
883 const size_t j = idx -
i * out_width;
885 dt_aligned_pixel_simd_t color_v;
886 if(
i % checker_1 <
i % checker_2)
888 if(j % checker_1 < j % checker_2) color_v = checker_color_2_v;
889 else color_v = checker_color_1_v;
893 if(j % checker_1 < j % checker_2) color_v = checker_color_1_v;
894 else color_v = checker_color_2_v;
897 const float opacity = opacities[
d->mask_type];
898 const float opacity_comp = 1.0f - opacity;
900 dt_aligned_pixel_simd_t image_v = dt_simd_max_zero(pix_out_v);
901 if(
d->mask_preview_black_and_white)
903 const float gray = 0.3f * image_v[0] + 0.59f * image_v[1] + 0.11f * image_v[2];
904 image_v[0] = image_v[1] = image_v[2] = gray;
906 pix_out_v = opacity_comp * color_v + opacity * image_v;
911 pix_out_v = dt_simd_max_zero(pix_out_v);
912 pix_out_v[3] = pix_in_v[3];
914 dt_store_simd_nontemporal(pix_out, pix_out_v);
1108 d->checker_color_1[0] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker1/red"), 0.f, 1.f);
1109 d->checker_color_1[1] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker1/green"), 0.f, 1.f);
1110 d->checker_color_1[2] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker1/blue"), 0.f, 1.f);
1112 d->checker_color_2[0] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker2/red"), 0.f, 1.f);
1113 d->checker_color_2[1] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker2/green"), 0.f, 1.f);
1114 d->checker_color_2[2] = CLAMP(
dt_conf_get_float(
"plugins/darkroom/colorbalancergb/checker2/blue"), 0.f, 1.f);
1115 d->checker_color_2[3] = 1.f;
1116 d->checker_size =
MAX(
dt_conf_get_int(
"plugins/darkroom/colorbalancergb/checker/size"), 2);
1117 d->mask_preview_black_and_white
1118 =
dt_conf_get_bool(
"plugins/darkroom/colorbalancergb/mask_preview/greyscaled");
1121 d->checker_color_1[3] =
d->mask_preview_black_and_white;
1128 d->vibrance =
p->vibrance;
1129 d->contrast = 1.0f +
p->contrast;
1130 d->grey_fulcrum =
p->grey_fulcrum;
1132 d->chroma_global =
p->chroma_global;
1133 d->chroma[0] =
p->chroma_shadows;
1134 d->chroma[1] =
p->chroma_midtones;
1135 d->chroma[2] =
p->chroma_highlights;
1138 d->saturation_global =
p->saturation_global;
1139 d->saturation[0] =
p->saturation_shadows;
1140 d->saturation[1] =
p->saturation_midtones;
1141 d->saturation[2] =
p->saturation_highlights;
1142 d->saturation[3] = 0.f;
1144 d->brilliance_global =
p->brilliance_global;
1145 d->brilliance[0] =
p->brilliance_shadows;
1146 d->brilliance[1] =
p->brilliance_midtones;
1147 d->brilliance[2] =
p->brilliance_highlights;
1148 d->brilliance[3] = 0.f;
1150 d->hue_angle =
M_PI *
p->hue_angle / 180.f;
1155 Ych_to_gradingRGB(Ych_norm, RGB_norm);
1160 Ych_to_gradingRGB(Ych,
d->global);
1161 for(
size_t c = 0; c < 4; c++)
d->global[c] = (
d->global[c] - RGB_norm[c]) + RGB_norm[c] *
p->global_Y;
1167 Ych_to_gradingRGB(Ych,
d->shadows);
1168 for(
size_t c = 0; c < 4; c++)
d->shadows[c] = 1.f + (
d->shadows[c] - RGB_norm[c]) +
p->shadows_Y;
1169 d->shadows_weight = 2.f +
p->shadows_weight * 2.f;
1175 Ych_to_gradingRGB(Ych,
d->highlights);
1176 for(
size_t c = 0; c < 4; c++)
d->highlights[c] = 1.f + (
d->highlights[c] - RGB_norm[c]) +
p->highlights_Y;
1177 d->highlights_weight = 2.f +
p->highlights_weight * 2.f;
1183 Ych_to_gradingRGB(Ych,
d->midtones);
1184 for(
size_t c = 0; c < 4; c++)
d->midtones[c] = 1.f / (1.f + (
d->midtones[c] - RGB_norm[c]));
1185 d->midtones_Y = 1.f / (1.f +
p->midtones_Y);
1186 d->white_fulcrum = exp2f(
p->white_fulcrum);
1187 d->midtones_weight = sqf(
d->shadows_weight) * sqf(
d->highlights_weight) /
1188 (sqf(
d->shadows_weight) + sqf(
d->highlights_weight));
1189 d->mask_grey_fulcrum = powf(
p->mask_grey_fulcrum, 0.4101205819200422f);
1192 if(
p->saturation_formula !=
d->saturation_formula)
d->lut_inited =
FALSE;
1193 d->saturation_formula =
p->saturation_formula;
1200 if(work_profile !=
d->work_profile)
1203 d->work_profile = work_profile;
1214 for(
size_t k = 0;
k <
LUT_ELEM;
k++) LUT_saturation[
k] = 0.f;
1227 for(
size_t b = 0; b <
STEPS; b++)
1230 (float)b / (
float)(
STEPS - 1), 0.f };
1232 float saturation = 0.f;
1235 dot_product(
rgb, input_matrix,
XYZ);
1238 dt_XYZ_2_JzAzBz(
XYZ, Jab);
1241 Jch[1] = dt_fast_hypotf(Jab[2], Jab[1]);
1242 Jch[2] = atan2f(Jab[2], Jab[1]);
1244 saturation = (Jch[0] > 0.f) ? Jch[1] / Jch[0] : 0.f;
1248 LUT_saturation[index] = fmaxf(saturation, LUT_saturation[index]);
1253 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;
1256 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;
1257 d->gamut_LUT[1] = (LUT_saturation[
LUT_ELEM - 1] + LUT_saturation[0] + LUT_saturation[1] + LUT_saturation[2] + LUT_saturation[3]) / 5.f;
1258 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;
1263 dt_aligned_pixel_t D65_xyY = { 0.31269999999999992f, 0.32899999999999996f , 1.f, 0.f };
1271 dot_product(RGB_red, input_matrix, XYZ_red);
1272 dot_product(RGB_green, input_matrix, XYZ_green);
1273 dot_product(RGB_blue, input_matrix, XYZ_blue);
1281 const float h_red = atan2f(xyY_red[1] - D65_xyY[1], xyY_red[0] - D65_xyY[0]);
1282 const float h_green = atan2f(xyY_green[1] - D65_xyY[1], xyY_green[0] - D65_xyY[0]);
1283 const float h_blue = atan2f(xyY_blue[1] - D65_xyY[1], xyY_blue[0] - D65_xyY[0]);
1285 float *
const restrict dt_UCS_LUT =
d->gamut_LUT;
1289 for(
int i = 0;
i < 50 * 360;
i++)
1291 const float angle = -
M_PI_F + ((float)
i) / (50.f * 360.f) * 2.f *
M_PI_F;
1292 const float tan_angle = tanf(angle);
1294 const float t_1 =
Delta_H(angle, h_blue) /
Delta_H(h_red, h_blue);
1295 const float t_2 =
Delta_H(angle, h_red) /
Delta_H(h_green, h_red);
1296 const float t_3 =
Delta_H(angle, h_green) /
Delta_H(h_blue, h_green);
1301 if(t_1 == CLAMP(t_1, 0, 1))
1303 const float t = (D65_xyY[1] - xyY_blue[1] + tan_angle * (xyY_blue[0] - D65_xyY[0]))
1304 / (xyY_red[1] - xyY_blue[1] + tan_angle * (xyY_blue[0] - xyY_red[0]));
1305 x_t = xyY_blue[0] +
t * (xyY_red[0] - xyY_blue[0]);
1306 y_t = xyY_blue[1] +
t * (xyY_red[1] - xyY_blue[1]);
1308 else if(t_2 == CLAMP(t_2, 0, 1))
1310 const float t = (D65_xyY[1] - xyY_red[1] + tan_angle * (xyY_red[0] - D65_xyY[0]))
1311 / (xyY_green[1] - xyY_red[1] + tan_angle * (xyY_red[0] - xyY_green[0]));
1312 x_t = xyY_red[0] +
t * (xyY_green[0] - xyY_red[0]);
1313 y_t = xyY_red[1] +
t * (xyY_green[1] - xyY_red[1]);
1315 else if(t_3 == CLAMP(t_3, 0, 1))
1317 const float t = (D65_xyY[1] - xyY_green[1] + tan_angle * (xyY_green[0] - D65_xyY[0]))
1318 / (xyY_blue[1] - xyY_green[1] + tan_angle * (xyY_green[0] - xyY_blue[0]));
1319 x_t = xyY_green[0] +
t * (xyY_blue[0] - xyY_green[0]);
1320 y_t = xyY_green[1] +
t * (xyY_blue[1] - xyY_green[1]);
1325 float UV_star_prime[2];
1329 const float H = atan2f(UV_star_prime[1], UV_star_prime[0]) * 180.f /
M_PI_F;
1330 const float H_round = roundf(
H);
1331 if(fabsf(
H - H_round) < 0.02f)
1333 int index = (int)(H_round + 180);
1334 index += (index < 0) ? 360 : 0;
1335 index -= (index > 359) ? 360 : 0;
1337 dt_UCS_LUT[index] = UV_star_prime[0] * UV_star_prime[0] + UV_star_prime[1] * UV_star_prime[1];
1343 d->lut_inited =
TRUE;
1541 const float shadows_weight = 2.f +
p->shadows_weight * 2.f;
1542 const float highlights_weight = 2.f +
p->highlights_weight * 2.f;
1545 GtkAllocation allocation;
1546 gtk_widget_get_allocation(widget, &allocation);
1547 GtkStyleContext *context = gtk_widget_get_style_context(widget);
1549 cairo_surface_t *cst =
1551 PangoFontDescription *desc =
1553 cairo_t *cr = cairo_create(cst);
1554 PangoLayout *layout = pango_cairo_create_layout(cr);
1556 const gint font_size = pango_font_description_get_size(desc);
1557 pango_font_description_set_size(desc, 0.95 * font_size);
1558 pango_layout_set_font_description(layout, desc);
1565 snprintf(text,
sizeof(text),
"X");
1566 pango_layout_set_text(layout, text, -1);
1567 pango_layout_get_pixel_extents(layout, &ink, NULL);
1568 const float line_height = ink.height;
1571 const float margin_top = inset;
1572 const float margin_bottom = line_height + 2 * inset;
1573 const float margin_left = line_height + inset;
1574 const float margin_right = 0;
1576 const float graph_width = allocation.width - margin_right - margin_left;
1577 const float graph_height = allocation.height - margin_bottom - margin_top;
1579 gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);
1582 cairo_pattern_t *grad;
1583 grad = cairo_pattern_create_linear(margin_left, 0.0, graph_width, 0.0);
1585 cairo_set_line_width(cr, 0.0);
1586 cairo_rectangle(cr, margin_left, graph_height + 2 * inset, graph_width, line_height);
1587 cairo_set_source(cr, grad);
1589 cairo_pattern_destroy(grad);
1592 const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, line_height);
1593 unsigned char *data = malloc(stride * graph_height);
1594 cairo_surface_t *surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, (
size_t)line_height, (
size_t)graph_height, stride);
1597 const size_t checker_2 = 2 * checker_1;
1599 for(
size_t i = 0;
i < (size_t)graph_height;
i++)
1600 for(
size_t j = 0; j < (size_t)line_height; j++)
1602 const size_t k = ((
i * (size_t)line_height) + j) * 4;
1603 unsigned char color;
1604 const float alpha = (float)
i / graph_height;
1605 if(
i % checker_1 <
i % checker_2)
1607 if(j % checker_1 < j % checker_2) color = 150;
1612 if(j % checker_1 < j % checker_2) color = 100;
1616 for(
size_t c = 0; c < 4; ++c) data[
k + c] = color * alpha;
1617 data[
k+3] = alpha * 255;
1620 cairo_set_source_surface(cr, surface, 0, margin_top);
1623 cairo_surface_destroy(surface);
1626 cairo_translate(cr, margin_left, margin_top);
1627 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
1630 cairo_rectangle(cr, 0, 0, graph_width, graph_height);
1631 cairo_fill_preserve(cr);
1635 const float midtones_weight
1636 = sqf(shadows_weight) * sqf(highlights_weight) / (sqf(shadows_weight) + sqf(highlights_weight));
1637 const float mask_grey_fulcrum = powf(
p->mask_grey_fulcrum, 0.4101205819200422f);
1644 const float Y =
k / (float)(
LUT_ELEM - 1);
1646 opacity_masks(Y, shadows_weight, highlights_weight, midtones_weight, mask_grey_fulcrum, output, NULL);
1647 for(
size_t c = 0; c < 3; c++) LUT[c][
k] = output[c];
1653 for(
size_t c = 0; c < 3; c++)
1655 GdkRGBA line_color = { fg_color.red * (1. - (2 - c) / 4.),
1656 fg_color.green * (1. - (2 - c) / 4.),
1657 fg_color.blue * (1. - (2 - c) / 4.),
1661 cairo_move_to(cr, 0, (1.f - LUT[c][0]) * graph_height);
1664 const float x = (float)
k / (
float)(
LUT_ELEM - 1) * graph_width;
1665 const float y = (1.f - LUT[c][
k]) * graph_height;
1666 cairo_line_to(cr,
x, y);
1676 pango_font_description_set_size(desc, font_size);
1677 pango_layout_set_font_description(layout, desc);
1680 cairo_set_source_surface(crf, cst, 0, 0);
1682 cairo_surface_destroy(cst);
1683 g_object_unref(layout);
1684 pango_font_description_free(desc);
1799 gtk_widget_set_tooltip_text(
g->hue_angle, _(
"rotate all hues by an angle, at the same luminance"));
1805 gtk_widget_set_tooltip_text(
g->vibrance, _(
"increase colorfulness mostly on low-chroma colors"));
1811 gtk_widget_set_tooltip_text(
g->contrast, _(
"increase the contrast at constant chromaticity"));
1819 gtk_widget_set_tooltip_text(
g->chroma_global, _(
"increase colorfulness at same luminance globally"));
1824 gtk_widget_set_tooltip_text(
g->chroma_shadows, _(
"increase colorfulness at same luminance mostly in shadows"));
1829 gtk_widget_set_tooltip_text(
g->chroma_midtones, _(
"increase colorfulness at same luminance mostly in mid-tones"));
1834 gtk_widget_set_tooltip_text(
g->chroma_highlights, _(
"increase colorfulness at same luminance mostly in highlights"));
1841 gtk_widget_set_tooltip_text(
g->saturation_global, _(
"add or remove saturation by an absolute amount"));
1846 gtk_widget_set_tooltip_text(
g->saturation_shadows, _(
"increase or decrease saturation proportionally to the original pixel saturation"));
1851 gtk_widget_set_tooltip_text(
g->saturation_midtones, _(
"increase or decrease saturation proportionally to the original pixel saturation"));
1856 gtk_widget_set_tooltip_text(
g->saturation_highlights, _(
"increase or decrease saturation proportionally to the original pixel saturation"));
1863 gtk_widget_set_tooltip_text(
g->brilliance_global, _(
"add or remove brilliance by an absolute amount"));
1868 gtk_widget_set_tooltip_text(
g->brilliance_shadows, _(
"increase or decrease brilliance proportionally to the original pixel brilliance"));
1873 gtk_widget_set_tooltip_text(
g->brilliance_midtones, _(
"increase or decrease brilliance proportionally to the original pixel brilliance"));
1878 gtk_widget_set_tooltip_text(
g->brilliance_highlights, _(
"increase or decrease brilliance proportionally to the original pixel brilliance"));
1889 gtk_widget_set_tooltip_text(
g->global_Y, _(
"global luminance offset"));
1894 gtk_widget_set_tooltip_text(
g->global_H, _(
"hue of the global color offset"));
1900 gtk_widget_set_tooltip_text(
g->global_C, _(
"chroma of the global color offset"));
1908 gtk_widget_set_tooltip_text(
g->shadows_Y, _(
"luminance gain in shadows"));
1913 gtk_widget_set_tooltip_text(
g->shadows_H, _(
"hue of the color gain in shadows"));
1919 gtk_widget_set_tooltip_text(
g->shadows_C, _(
"chroma of the color gain in shadows"));
1927 gtk_widget_set_tooltip_text(
g->highlights_Y, _(
"luminance gain in highlights"));
1932 gtk_widget_set_tooltip_text(
g->highlights_H, _(
"hue of the color gain in highlights"));
1938 gtk_widget_set_tooltip_text(
g->highlights_C, _(
"chroma of the color gain in highlights"));
1946 gtk_widget_set_tooltip_text(
g->midtones_Y, _(
"luminance exponent in mid-tones"));
1951 gtk_widget_set_tooltip_text(
g->midtones_H, _(
"hue of the color exponent in mid-tones"));
1957 gtk_widget_set_tooltip_text(
g->midtones_C, _(
"chroma of the color exponent in mid-tones"));
1963 gtk_widget_set_tooltip_text(
g->saturation_formula, _(
"choose in which uniform color space the saturation is computed."));
1967 g->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
1968 gtk_widget_set_hexpand(GTK_WIDGET(
g->area),
TRUE);
1969 g_object_set_data(G_OBJECT(
g->area),
"iop-instance", self);
1971 gtk_box_pack_start(GTK_BOX(self->
widget),
1973 "plugins/darkroom/colorbalancergb/graphheight", 200, 100),
1981 gtk_widget_set_tooltip_text(
g->shadows_weight, _(
"weight of the shadows over the whole tonal range"));
1984 g_signal_connect(G_OBJECT(
g->shadows_weight),
"quad-pressed", G_CALLBACK(
mask_callback), self);
1989 gtk_widget_set_tooltip_text(
g->mask_grey_fulcrum, _(
"position of the middle-gray reference for masking"));
1992 g_signal_connect(G_OBJECT(
g->mask_grey_fulcrum),
"quad-pressed", G_CALLBACK(
mask_callback), self);
1997 gtk_widget_set_tooltip_text(
g->highlights_weight, _(
"weights of highlights over the whole tonal range"));
2000 g_signal_connect(G_OBJECT(
g->highlights_weight),
"quad-pressed", G_CALLBACK(
mask_callback), self);
2007 gtk_widget_set_tooltip_text(
g->white_fulcrum, _(
"peak white luminance value used to normalize the power function"));
2013 gtk_widget_set_tooltip_text(
g->grey_fulcrum, _(
"peak gray luminance value used to normalize the power function"));
2049 Ych_to_XYZ(Ych,
XYZ);
2050 dt_XYZ_to_Rec709_D65(
XYZ,
RGB);
2051 const float max_RGB = fmaxf(fmaxf(
RGB[0],
RGB[1]),
RGB[2]);
2052 for(
size_t c = 0; c < 3; c++)
RGB[c] = powf(
RGB[c] / max_RGB, 1.f / 2.2f);
2058 const float Y = 0.f + stop;
2066 self->
widget = GTK_WIDGET(
g->notebook);