diff --git a/src/common/colorspaces.c b/src/common/colorspaces.c index 89ea852493dd..9c6016586916 100644 --- a/src/common/colorspaces.c +++ b/src/common/colorspaces.c @@ -101,13 +101,13 @@ static const dt_colorspaces_color_profile_t *_get_profile const char *filename, dt_colorspaces_profile_direction_t direction); -static int dt_colorspaces_get_matrix_from_profile(cmsHPROFILE prof, - dt_colormatrix_t matrix, - float *lutr, - float *lutg, - float *lutb, - const int lutsize, - const int input) +static int _colorspaces_get_matrix_from_profile(cmsHPROFILE prof, + dt_colormatrix_t matrix, + float *lutr, + float *lutg, + float *lutb, + const int lutsize, + const int input) { // create an OpenCL processable matrix + tone curves from an cmsHPROFILE: // NOTE: may be invoked with matrix and LUT pointers set to null to find @@ -235,7 +235,7 @@ int dt_colorspaces_get_matrix_from_input_profile(cmsHPROFILE prof, float *lutb, const int lutsize) { - return dt_colorspaces_get_matrix_from_profile(prof, matrix, lutr, lutg, lutb, lutsize, 1); + return _colorspaces_get_matrix_from_profile(prof, matrix, lutr, lutg, lutb, lutsize, 1); } int dt_colorspaces_get_matrix_from_output_profile(cmsHPROFILE prof, @@ -245,10 +245,10 @@ int dt_colorspaces_get_matrix_from_output_profile(cmsHPROFILE prof, float *lutb, const int lutsize) { - return dt_colorspaces_get_matrix_from_profile(prof, matrix, lutr, lutg, lutb, lutsize, 0); + return _colorspaces_get_matrix_from_profile(prof, matrix, lutr, lutg, lutb, lutsize, 0); } -static cmsHPROFILE dt_colorspaces_create_lab_profile() +static cmsHPROFILE _colorspaces_create_lab_profile() { return cmsCreateLab4Profile(cmsD50_xyY()); } @@ -431,7 +431,7 @@ static cmsHPROFILE dt_colorspaces_create_srgb_profile_v4() return _colorspaces_create_srgb_profile(FALSE); } -static cmsHPROFILE dt_colorspaces_create_brg_profile() +static cmsHPROFILE _colorspaces_create_brg_profile() { cmsFloat64Number srgb_parameters[5] = { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 }; @@ -449,7 +449,7 @@ static cmsHPROFILE dt_colorspaces_create_brg_profile() return profile; } -static cmsHPROFILE dt_colorspaces_create_gamma_rec709_rgb_profile(void) +static cmsHPROFILE _colorspaces_create_gamma_rec709_rgb_profile(void) { cmsFloat64Number srgb_parameters[5] = { 1/0.45, 1.0 / 1.099, 0.099 / 1.099, 1.0 / 4.5, 0.081 }; @@ -631,7 +631,7 @@ cmsHPROFILE dt_colorspaces_create_darktable_profile(const char *makermodel) return hp; } -static cmsHPROFILE dt_colorspaces_create_xyz_profile(void) +static cmsHPROFILE _colorspaces_create_xyz_profile(void) { cmsHPROFILE hXYZ = cmsCreateXYZProfile(); cmsSetPCS(hXYZ, cmsSigXYZData); @@ -670,7 +670,7 @@ static cmsHPROFILE dt_colorspaces_create_linear_rec709_rgb_profile(void) return profile; } -static cmsHPROFILE dt_colorspaces_create_linear_rec2020_rgb_profile(void) +static cmsHPROFILE _colorspaces_create_linear_rec2020_rgb_profile(void) { cmsToneCurve *transferFunction = cmsBuildGamma(NULL, 1.0); @@ -683,7 +683,7 @@ static cmsHPROFILE dt_colorspaces_create_linear_rec2020_rgb_profile(void) return profile; } -static cmsHPROFILE dt_colorspaces_create_pq_rec2020_rgb_profile(void) +static cmsHPROFILE _colorspaces_create_pq_rec2020_rgb_profile(void) { cmsToneCurve *transferFunction = _colorspaces_create_transfer(4096, _PQ_fct); @@ -696,7 +696,7 @@ static cmsHPROFILE dt_colorspaces_create_pq_rec2020_rgb_profile(void) return profile; } -static cmsHPROFILE dt_colorspaces_create_hlg_rec2020_rgb_profile(void) +static cmsHPROFILE _colorspaces_create_hlg_rec2020_rgb_profile(void) { cmsToneCurve *transferFunction = _colorspaces_create_transfer(4096, _HLG_fct); @@ -709,7 +709,7 @@ static cmsHPROFILE dt_colorspaces_create_hlg_rec2020_rgb_profile(void) return profile; } -static cmsHPROFILE dt_colorspaces_create_pq_p3_rgb_profile(void) +static cmsHPROFILE _colorspaces_create_pq_p3_rgb_profile(void) { cmsToneCurve *transferFunction = _colorspaces_create_transfer(4096, _PQ_fct); @@ -722,7 +722,7 @@ static cmsHPROFILE dt_colorspaces_create_pq_p3_rgb_profile(void) return profile; } -static cmsHPROFILE dt_colorspaces_create_hlg_p3_rgb_profile(void) +static cmsHPROFILE _colorspaces_create_hlg_p3_rgb_profile(void) { cmsToneCurve *transferFunction = _colorspaces_create_transfer(4096, _HLG_fct); @@ -735,7 +735,7 @@ static cmsHPROFILE dt_colorspaces_create_hlg_p3_rgb_profile(void) return profile; } -static cmsHPROFILE dt_colorspaces_create_display_p3_rgb_profile(void) +static cmsHPROFILE _colorspaces_create_display_p3_rgb_profile(void) { cmsFloat64Number srgb_parameters[5] = { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 }; @@ -750,7 +750,7 @@ static cmsHPROFILE dt_colorspaces_create_display_p3_rgb_profile(void) return profile; } -static cmsHPROFILE dt_colorspaces_create_linear_prophoto_rgb_profile(void) +static cmsHPROFILE _colorspaces_create_linear_prophoto_rgb_profile(void) { cmsToneCurve *transferFunction = cmsBuildGamma(NULL, 1.0); @@ -763,7 +763,7 @@ static cmsHPROFILE dt_colorspaces_create_linear_prophoto_rgb_profile(void) return profile; } -static cmsHPROFILE dt_colorspaces_create_linear_infrared_profile(void) +static cmsHPROFILE _colorspaces_create_linear_infrared_profile(void) { cmsToneCurve *transferFunction = cmsBuildGamma(NULL, 1.0); @@ -1046,6 +1046,25 @@ void dt_colorspaces_cleanup_profile(cmsHPROFILE p) cmsCloseProfile(p); } +cmsHPROFILE dt_colorspaces_make_temporary_profile(cmsHPROFILE profile) +{ + cmsUInt32Number size; + cmsHPROFILE old_profile = profile; + profile = NULL; + + if(old_profile && cmsSaveProfileToMem(old_profile, NULL, &size)) + { + char *data = malloc(size); + + if(cmsSaveProfileToMem(old_profile, data, &size)) + profile = cmsOpenProfileFromMem(data, size); + + free(data); + } + + return profile; +} + void dt_colorspaces_get_profile_name(cmsHPROFILE p, const char *language, const char *country, @@ -1446,14 +1465,14 @@ dt_colorspaces_t *dt_colorspaces_init() res->profiles = g_list_append (res->profiles, - _create_profile(DT_COLORSPACE_REC709, dt_colorspaces_create_gamma_rec709_rgb_profile(), + _create_profile(DT_COLORSPACE_REC709, _colorspaces_create_gamma_rec709_rgb_profile(), _("Rec709 RGB"), ++in_pos, ++out_pos, -1, -1, ++work_pos, -1)); res->profiles = g_list_append (res->profiles, _create_profile(DT_COLORSPACE_LIN_REC2020, - dt_colorspaces_create_linear_rec2020_rgb_profile(), + _colorspaces_create_linear_rec2020_rgb_profile(), _("linear Rec2020 RGB"), ++in_pos, ++out_pos, ++display_pos, ++category_pos, ++work_pos, ++display2_pos)); @@ -1461,7 +1480,7 @@ dt_colorspaces_t *dt_colorspaces_init() res->profiles = g_list_append (res->profiles, _create_profile(DT_COLORSPACE_PQ_REC2020, - dt_colorspaces_create_pq_rec2020_rgb_profile(), + _colorspaces_create_pq_rec2020_rgb_profile(), _("PQ Rec2020 RGB"), ++in_pos, ++out_pos, ++display_pos, ++category_pos, ++work_pos, ++display2_pos)); @@ -1469,27 +1488,27 @@ dt_colorspaces_t *dt_colorspaces_init() res->profiles = g_list_append (res->profiles, _create_profile(DT_COLORSPACE_HLG_REC2020, - dt_colorspaces_create_hlg_rec2020_rgb_profile(), + _colorspaces_create_hlg_rec2020_rgb_profile(), _("HLG Rec2020 RGB"), ++in_pos, ++out_pos, ++display_pos, ++category_pos, ++work_pos, ++display2_pos)); res->profiles = g_list_append (res->profiles, - _create_profile(DT_COLORSPACE_PQ_P3, dt_colorspaces_create_pq_p3_rgb_profile(), + _create_profile(DT_COLORSPACE_PQ_P3, _colorspaces_create_pq_p3_rgb_profile(), _("PQ P3 RGB"), ++in_pos, ++out_pos, ++display_pos, ++category_pos, ++work_pos, ++display2_pos)); res->profiles = g_list_append (res->profiles, - _create_profile(DT_COLORSPACE_HLG_P3, dt_colorspaces_create_hlg_p3_rgb_profile(), + _create_profile(DT_COLORSPACE_HLG_P3, _colorspaces_create_hlg_p3_rgb_profile(), _("HLG P3 RGB"), ++in_pos, ++out_pos, ++display_pos, ++category_pos, ++work_pos, ++display2_pos)); res->profiles = g_list_append (res->profiles, _create_profile(DT_COLORSPACE_DISPLAY_P3, - dt_colorspaces_create_display_p3_rgb_profile(), + _colorspaces_create_display_p3_rgb_profile(), _("Display P3 RGB"), ++in_pos, ++out_pos, ++display_pos, ++category_pos, ++work_pos, ++display2_pos)); @@ -1497,7 +1516,7 @@ dt_colorspaces_t *dt_colorspaces_init() res->profiles = g_list_append (res->profiles, _create_profile(DT_COLORSPACE_PROPHOTO_RGB, - dt_colorspaces_create_linear_prophoto_rgb_profile(), + _colorspaces_create_linear_prophoto_rgb_profile(), _("linear ProPhoto RGB"), ++in_pos, ++out_pos, ++display_pos, ++category_pos, ++work_pos, ++display2_pos)); @@ -1505,26 +1524,26 @@ dt_colorspaces_t *dt_colorspaces_init() res->profiles = g_list_append (res->profiles, _create_profile(DT_COLORSPACE_XYZ, - dt_colorspaces_create_xyz_profile(), _("linear XYZ"), ++in_pos, + _colorspaces_create_xyz_profile(), _("linear XYZ"), ++in_pos, dt_conf_get_bool("allow_lab_output") ? ++out_pos : -1, -1, -1, -1, -1)); res->profiles = g_list_append (res->profiles, _create_profile(DT_COLORSPACE_LAB, - dt_colorspaces_create_lab_profile(), _("Lab"), ++in_pos, + _colorspaces_create_lab_profile(), _("Lab"), ++in_pos, dt_conf_get_bool("allow_lab_output") ? ++out_pos : -1, -1, -1, -1, -1)); res->profiles = g_list_append (res->profiles, _create_profile(DT_COLORSPACE_INFRARED, - dt_colorspaces_create_linear_infrared_profile(), + _colorspaces_create_linear_infrared_profile(), _("linear infrared BGR"), ++in_pos, -1, -1, -1, -1, -1)); res->profiles = g_list_append (res->profiles, - _create_profile(DT_COLORSPACE_BRG, dt_colorspaces_create_brg_profile(), + _create_profile(DT_COLORSPACE_BRG, _colorspaces_create_brg_profile(), _("BRG (for testing)"), ++in_pos, ++out_pos, ++display_pos, -1, -1, ++display2_pos)); diff --git a/src/common/colorspaces.h b/src/common/colorspaces.h index b95e2bcedf9d..c12a0fc6d11c 100644 --- a/src/common/colorspaces.h +++ b/src/common/colorspaces.h @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2010-2023 darktable developers. + Copyright (C) 2010-2024 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -267,6 +267,9 @@ int dt_colorspaces_get_matrix_from_output_profile(cmsHPROFILE prof, float *lutb, const int lutsize); +/** create a temporary profile to be removed by dt_colorspaces_cleanup_profile */ +cmsHPROFILE dt_colorspaces_make_temporary_profile(cmsHPROFILE profile); + /** wrapper to get the name from a color profile. this tries to handle character encodings. */ void dt_colorspaces_get_profile_name(cmsHPROFILE p, const char *language, diff --git a/src/iop/colorout.c b/src/iop/colorout.c index 5a8fc75596d3..2b85073a9c39 100644 --- a/src/iop/colorout.c +++ b/src/iop/colorout.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2009-2023 darktable developers. + Copyright (C) 2009-2024 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -573,25 +573,6 @@ void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const } } -static cmsHPROFILE _make_clipping_profile(cmsHPROFILE profile) -{ - cmsUInt32Number size; - cmsHPROFILE old_profile = profile; - profile = NULL; - - if(old_profile && cmsSaveProfileToMem(old_profile, NULL, &size)) - { - char *data = malloc(size); - - if(cmsSaveProfileToMem(old_profile, data, &size)) - profile = cmsOpenProfileFromMem(data, size); - - free(data); - } - - return profile; -} - 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) { @@ -600,7 +581,7 @@ void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pix d->type = p->type; - const int force_lcms2 = dt_conf_get_bool("plugins/lighttable/export/force_lcms2"); + const gboolean force_lcms2 = dt_conf_get_bool("plugins/lighttable/export/force_lcms2"); dt_colorspaces_color_profile_type_t out_type = DT_COLORSPACE_SRGB; gchar *out_filename = NULL; @@ -724,7 +705,7 @@ void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pix // taking a roundtrip through those profiles during softproofing has no effect. as a workaround we have to // make lcms quantisize those gamma tables to get the desired effect. // in case that fails we don't enable softproofing. - softproof = _make_clipping_profile(softproof); + softproof = dt_colorspaces_make_temporary_profile(softproof); if(softproof) { /* TODO: the use of bpc should be userconfigurable either from module or preference pane */ @@ -798,7 +779,7 @@ void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pix d->unbounded_coeffs[k][0] = -1.0f; } - // softproof is never the original but always a copy that went through _make_clipping_profile() + // softproof is never the original but always a copy that went through dt_colorspaces_make_temporary_profile() dt_colorspaces_cleanup_profile(softproof); dt_ioppr_set_pipe_output_profile_info(self->dev, piece->pipe, d->type, out_filename, p->intent); @@ -861,7 +842,7 @@ static void _preference_changed(gpointer instance, gpointer user_data) dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_colorout_gui_data_t *g = (dt_iop_colorout_gui_data_t *)self->gui_data; - const int force_lcms2 = dt_conf_get_bool("plugins/lighttable/export/force_lcms2"); + const gboolean force_lcms2 = dt_conf_get_bool("plugins/lighttable/export/force_lcms2"); if(force_lcms2) { gtk_widget_set_no_show_all(g->output_intent, FALSE); @@ -876,7 +857,7 @@ static void _preference_changed(gpointer instance, gpointer user_data) void gui_init(struct dt_iop_module_t *self) { - const int force_lcms2 = dt_conf_get_bool("plugins/lighttable/export/force_lcms2"); + const gboolean force_lcms2 = dt_conf_get_bool("plugins/lighttable/export/force_lcms2"); dt_iop_colorout_gui_data_t *g = IOP_GUI_ALLOC(colorout); diff --git a/src/libs/histogram.c b/src/libs/histogram.c index aca2a2045a1b..0cf737755a41 100644 --- a/src/libs/histogram.c +++ b/src/libs/histogram.c @@ -1013,33 +1013,36 @@ static void dt_lib_histogram_process // Convert pixelpipe output in display RGB to histogram profile. If // in tether view, then the image is already converted by the // caller. - // - // FIXME: do conversion in-place in the processing to save an extra - // buffer? -- at least for waveform, which already has to touch each - // pixel -- will need logic from _transform_matrix_rgb() -- or - // better yet a per-pixel callback within - // _transform_matrix_rgb()-ish code float *img_display = dt_alloc_align_float((size_t)4 * width * height); if(!img_display) return; - // In case of vectorscope we make sure a valid colorspace transform even - // if the to_profile has no matrix and falls back to Rec2020 so we see the - // result of a relative colorimetric conversion to the histogram profile... - const gboolean replaced = d->scope_type == DT_LIB_HISTOGRAM_SCOPE_VECTORSCOPE - && (!profile_info_to || !dt_is_valid_colormatrix(profile_info_to->matrix_in[0][0])); - if(replaced) + // FIXME: we might get called with profile_info_to == NULL due to caller errors + // like having a non cmsSigRgbData colorspace used in softproofing. + // As dt_ioppr_transform_image_colorspace_rgb will fail to provide data in img_display + // we currently do a fallback to Rec2020. + // For correct softproofing support we would have to convert data as we do in colorout. + const gboolean fallback = !profile_info_to || !dt_is_valid_colormatrix(profile_info_to->matrix_in[0][0]); + static gboolean noted = FALSE; + if(fallback) { - dt_print(DT_DEBUG_ALWAYS, - "[histogram] unsupported vectorscope profile %i %s," + if(!noted) + { + dt_print(DT_DEBUG_ALWAYS, + "[histogram] %s profile %i %s," " it will be replaced with linear Rec2020\n", + profile_info_to ? "undefined" : "invalid", profile_info_to ? profile_info_to->type : 0, - profile_info_to ? profile_info_to->filename : "unsupported"); - dt_control_log(_("unsupported vectorscope profile selected," + profile_info_to ? profile_info_to->filename : ""); + dt_control_log(_("unsupported profile selected for histogram," " it will be replaced with linear Rec2020")); + noted = TRUE; + } } + else + noted = FALSE; - const dt_iop_order_iccprofile_info_t *profile_info_out = replaced + const dt_iop_order_iccprofile_info_t *profile_info_out = fallback ? dt_ioppr_add_profile_info_to_list(darktable.develop, DT_COLORSPACE_LIN_REC2020, "", DT_INTENT_RELATIVE_COLORIMETRIC) : profile_info_to;