diff options
-rw-r--r-- | release/scripts/startup/bl_ui/properties_output.py | 36 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_image_save.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image_format.cc | 27 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image_save.cc | 69 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_templates.c | 7 | ||||
-rw-r--r-- | source/blender/editors/space_image/image_buttons.c | 30 | ||||
-rw-r--r-- | source/blender/editors/space_image/image_ops.c | 21 | ||||
-rw-r--r-- | source/blender/imbuf/IMB_colormanagement.h | 1 | ||||
-rw-r--r-- | source/blender/imbuf/intern/colormanagement.c | 38 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_scene_types.h | 6 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_color.c | 5 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_scene.c | 56 | ||||
-rw-r--r-- | source/blender/nodes/composite/nodes/node_composite_output_file.cc | 16 | ||||
-rw-r--r-- | source/blender/render/intern/render_result.c | 2 |
14 files changed, 262 insertions, 55 deletions
diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py index 34e86184097..312a580bf7d 100644 --- a/release/scripts/startup/bl_ui/properties_output.py +++ b/release/scripts/startup/bl_ui/properties_output.py @@ -296,6 +296,41 @@ class RENDER_PT_output_views(RenderOutputButtonsPanel, Panel): layout.template_image_views(rd.image_settings) +class RENDER_PT_output_color_management(RenderOutputButtonsPanel, Panel): + bl_label = "Color Management" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = "RENDER_PT_output" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + scene = context.scene + image_settings = scene.render.image_settings + + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + layout.row().prop(image_settings, "color_management", text=" ", expand=True) + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) + + if image_settings.color_management == 'OVERRIDE': + owner = image_settings + else: + owner = scene + flow.enabled = False + + col = flow.column() + + if image_settings.has_linear_colorspace: + if hasattr(owner, 'linear_colorspace_settings'): + col.prop(owner.linear_colorspace_settings, "name", text="Color Space") + else: + col.prop(owner.display_settings, "display_device") + col.separator() + col.template_colormanaged_view_settings(owner, "view_settings") + + class RENDER_PT_encoding(RenderOutputButtonsPanel, Panel): bl_label = "Encoding" bl_parent_id = "RENDER_PT_output" @@ -484,6 +519,7 @@ classes = ( RENDER_PT_stereoscopy, RENDER_PT_output, RENDER_PT_output_views, + RENDER_PT_output_color_management, RENDER_PT_encoding, RENDER_PT_encoding_video, RENDER_PT_encoding_audio, diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h index f9d07387463..b022e677845 100644 --- a/source/blender/blenkernel/BKE_image_save.h +++ b/source/blender/blenkernel/BKE_image_save.h @@ -47,7 +47,7 @@ bool BKE_image_save(struct ReportList *reports, struct ImageUser *iuser, struct ImageSaveOptions *opts); -/* Lower level image writing. */ +/* Render saving. */ /* Save single or multilayer OpenEXR files from the render result. * Optionally saves only a specific view or layer. */ @@ -55,6 +55,7 @@ bool BKE_image_render_write_exr(struct ReportList *reports, const struct RenderResult *rr, const char *filename, const struct ImageFormatData *imf, + const bool save_as_render, const char *view, int layer); diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc index 0783e343ec9..44aa9e21195 100644 --- a/source/blender/blenkernel/intern/image_format.cc +++ b/source/blender/blenkernel/intern/image_format.cc @@ -904,8 +904,27 @@ void BKE_image_format_init_for_write(ImageFormatData *imf, { *imf = (imf_src) ? *imf_src : scene_src->r.im_format; - /* Use general scene settings also used for display. */ - BKE_color_managed_display_settings_copy(&imf->display_settings, &scene_src->display_settings); - BKE_color_managed_view_settings_copy(&imf->view_settings, &scene_src->view_settings); - BKE_color_managed_colorspace_settings_init(&imf->linear_colorspace_settings); + if (imf_src && imf_src->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) { + /* Use settings specific to one node, image save operation, etc. */ + BKE_color_managed_display_settings_copy(&imf->display_settings, &imf_src->display_settings); + BKE_color_managed_view_settings_copy(&imf->view_settings, &imf_src->view_settings); + BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings, + &imf_src->linear_colorspace_settings); + } + else if (scene_src->r.im_format.color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) { + /* Use scene settings specific to render output. */ + BKE_color_managed_display_settings_copy(&imf->display_settings, + &scene_src->r.im_format.display_settings); + BKE_color_managed_view_settings_copy(&imf->view_settings, + &scene_src->r.im_format.view_settings); + BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings, + &scene_src->r.im_format.linear_colorspace_settings); + } + else { + /* Use general scene settings also used for display. */ + BKE_color_managed_display_settings_copy(&imf->display_settings, &scene_src->display_settings); + BKE_color_managed_view_settings_copy(&imf->view_settings, &scene_src->view_settings); + STRNCPY(imf->linear_colorspace_settings.name, + IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR)); + } } diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index b7f234aea59..f530183f967 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -11,6 +11,7 @@ #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_vector.hh" #include "DNA_image_types.h" @@ -31,6 +32,8 @@ #include "RE_pipeline.h" +using blender::Vector; + void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene) { memset(opts, 0, sizeof(*opts)); @@ -220,14 +223,16 @@ static bool image_save_single(ReportList *reports, /* fancy multiview OpenEXR */ if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { /* save render result */ - ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, nullptr, layer); + ok = BKE_image_render_write_exr( + reports, rr, opts->filepath, imf, save_as_render, nullptr, layer); image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed); BKE_image_release_ibuf(ima, ibuf, lock); } /* regular mono pipeline */ else if (is_mono) { if (is_exr_rr) { - ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, nullptr, layer); + ok = BKE_image_render_write_exr( + reports, rr, opts->filepath, imf, save_as_render, nullptr, layer); } else { colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf); @@ -261,7 +266,8 @@ static bool image_save_single(ReportList *reports, if (is_exr_rr) { BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath); - ok_view = BKE_image_render_write_exr(reports, rr, filepath, imf, view, layer); + ok_view = BKE_image_render_write_exr( + reports, rr, filepath, imf, save_as_render, view, layer); image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed); } else { @@ -307,7 +313,8 @@ static bool image_save_single(ReportList *reports, /* stereo (multiview) images */ else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) { if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) { - ok = BKE_image_render_write_exr(reports, rr, opts->filepath, imf, nullptr, layer); + ok = BKE_image_render_write_exr( + reports, rr, opts->filepath, imf, save_as_render, nullptr, layer); image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed); BKE_image_release_ibuf(ima, ibuf, lock); } @@ -450,10 +457,38 @@ bool BKE_image_save( /* OpenEXR saving, single and multilayer. */ +static float *image_exr_from_scene_linear_to_output(float *rect, + const int width, + const int height, + const int channels, + const ImageFormatData *imf, + Vector<float *> &tmp_output_rects) +{ + if (imf == nullptr) { + return rect; + } + + const char *to_colorspace = imf->linear_colorspace_settings.name; + if (to_colorspace[0] == '\0' || IMB_colormanagement_space_name_is_scene_linear(to_colorspace)) { + return rect; + } + + float *output_rect = (float *)MEM_dupallocN(rect); + tmp_output_rects.append(output_rect); + + const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get( + COLOR_ROLE_SCENE_LINEAR); + IMB_colormanagement_transform( + output_rect, width, height, channels, from_colorspace, to_colorspace, false); + + return output_rect; +} + bool BKE_image_render_write_exr(ReportList *reports, const RenderResult *rr, - const char *filename, + const char *filepath, const ImageFormatData *imf, + const bool save_as_render, const char *view, int layer) { @@ -461,6 +496,7 @@ bool BKE_image_render_write_exr(ReportList *reports, const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16); const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR); const bool write_z = !multi_layer && (imf && (imf->flag & R_IMF_FLAG_ZBUF)); + Vector<float *> tmp_output_rects; /* Write first layer if not multilayer and no layer was specified. */ if (!multi_layer && layer == -1) { @@ -498,7 +534,10 @@ bool BKE_image_render_write_exr(ReportList *reports, continue; } - float *output_rect = rview->rectf; + float *output_rect = (save_as_render) ? + image_exr_from_scene_linear_to_output( + rview->rectf, rr->rectx, rr->recty, 4, imf, tmp_output_rects) : + rview->rectf; for (int a = 0; a < 4; a++) { char passname[EXR_PASS_MAXNAME]; @@ -556,7 +595,11 @@ bool BKE_image_render_write_exr(ReportList *reports, const bool pass_RGBA = (STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A")); const bool pass_half_float = half_float && pass_RGBA; - float *output_rect = rp->rect; + /* Colorspace conversion only happens on RGBA passes. */ + float *output_rect = (save_as_render && pass_RGBA) ? + image_exr_from_scene_linear_to_output( + rp->rect, rr->rectx, rr->recty, 4, imf, tmp_output_rects) : + rp->rect; for (int a = 0; a < rp->channels; a++) { /* Save Combined as RGBA if single layer save. */ @@ -587,11 +630,11 @@ bool BKE_image_render_write_exr(ReportList *reports, errno = 0; - BLI_make_existing_file(filename); + BLI_make_existing_file(filepath); int compress = (imf ? imf->exr_codec : 0); bool success = IMB_exr_begin_write( - exrhandle, filename, rr->rectx, rr->recty, compress, rr->stamp_data); + exrhandle, filepath, rr->rectx, rr->recty, compress, rr->stamp_data); if (success) { IMB_exr_write_channels(exrhandle); } @@ -601,6 +644,10 @@ bool BKE_image_render_write_exr(ReportList *reports, reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno)); } + for (float *rect : tmp_output_rects) { + MEM_freeN(rect); + } + IMB_exr_close(exrhandle); return success; } @@ -664,7 +711,7 @@ bool BKE_image_render_write(ReportList *reports, const float dither = scene->r.dither_intensity; if (image_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { - ok = BKE_image_render_write_exr(reports, rr, filename, &image_format, nullptr, -1); + ok = BKE_image_render_write_exr(reports, rr, filename, &image_format, true, nullptr, -1); image_render_print_save_message(reports, filename, ok, errno); } @@ -682,7 +729,7 @@ bool BKE_image_render_write(ReportList *reports, } if (is_exr_rr) { - ok = BKE_image_render_write_exr(reports, rr, filepath, &image_format, rv->name, -1); + ok = BKE_image_render_write_exr(reports, rr, filepath, &image_format, true, rv->name, -1); image_render_print_save_message(reports, filepath, ok, errno); /* optional preview images for exr */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 077eedd6e58..38499a7f089 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6223,16 +6223,13 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, ColorManagedViewSettings *view_settings = view_transform_ptr.data; uiLayout *col = uiLayoutColumn(layout, false); - - uiLayout *row = uiLayoutRow(col, false); - uiItemR(row, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE); + uiItemR(col, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE); + uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE); col = uiLayoutColumn(layout, false); uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE); uiItemR(col, &view_transform_ptr, "gamma", 0, NULL, ICON_NONE); - uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE); - col = uiLayoutColumn(layout, false); uiItemR(col, &view_transform_ptr, "use_curve_mapping", 0, NULL, ICON_NONE); if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) { diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index abde5f52bb0..208928afc1f 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -958,14 +958,11 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma { ImageFormatData *imf = imfptr->data; ID *id = imfptr->owner_id; - PointerRNA display_settings_ptr; - PropertyRNA *prop; const int depth_ok = BKE_imtype_valid_depths(imf->imtype); /* some settings depend on this being a scene that's rendered */ const bool is_render_out = (id && GS(id->name) == ID_SCE); uiLayout *col; - bool show_preview = false; col = uiLayoutColumn(layout, false); @@ -1005,7 +1002,6 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma } if (is_render_out && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) { - show_preview = true; uiItemR(col, imfptr, "use_preview", 0, NULL, ICON_NONE); } @@ -1037,18 +1033,22 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma uiItemR(col, imfptr, "tiff_codec", 0, NULL, ICON_NONE); } - /* color management */ - if (color_management && (!BKE_imtype_requires_linear_float(imf->imtype) || - (show_preview && imf->flag & R_IMF_FLAG_PREVIEW_JPG))) { - prop = RNA_struct_find_property(imfptr, "display_settings"); - display_settings_ptr = RNA_property_pointer_get(imfptr, prop); - - col = uiLayoutColumn(layout, false); - uiItemL(col, IFACE_("Color Management"), ICON_NONE); - - uiItemR(col, &display_settings_ptr, "display_device", 0, NULL, ICON_NONE); + /* Override color management */ + if (color_management) { + uiItemS(col); + uiItemR(col, imfptr, "color_management", 0, NULL, ICON_NONE); - uiTemplateColormanagedViewSettings(col, NULL, imfptr, "view_settings"); + if (imf->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) { + if (BKE_imtype_requires_linear_float(imf->imtype)) { + PointerRNA linear_settings_ptr = RNA_pointer_get(imfptr, "linear_colorspace_settings"); + uiItemR(col, &linear_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE); + } + else { + PointerRNA display_settings_ptr = RNA_pointer_get(imfptr, "display_settings"); + uiItemR(col, &display_settings_ptr, "display_device", 0, NULL, ICON_NONE); + uiTemplateColormanagedViewSettings(col, NULL, imfptr, "view_settings"); + } + } } } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index c4d69d589bf..1c4a1d7e8c9 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1737,7 +1737,7 @@ static int image_save_options_init(Main *bmain, if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) { /* imtype */ - BKE_image_format_copy(&opts->im_format, &scene->r.im_format); + BKE_image_format_init_for_write(&opts->im_format, scene, NULL); is_depth_set = true; if (!BKE_image_is_multiview(ima)) { /* In case multiview is disabled, @@ -1759,8 +1759,12 @@ static int image_save_options_init(Main *bmain, /* use the multiview image settings as the default */ opts->im_format.stereo3d_format = *ima->stereo3d_format; opts->im_format.views_format = ima->views_format; + + BKE_image_format_color_management_copy_from_scene(&opts->im_format, scene); } + opts->im_format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE; + if (ima->source == IMA_SRC_TILED) { BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath)); BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); @@ -1810,9 +1814,6 @@ static int image_save_options_init(Main *bmain, STR_CONCAT(opts->filepath, len, ".<UDIM>"); } } - - /* color management */ - BKE_image_format_color_management_copy_from_scene(&opts->im_format, scene); } BKE_image_release_ibuf(ima, ibuf, lock); @@ -2002,15 +2003,21 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op) ImageSaveData *isd = op->customdata; PointerRNA imf_ptr; const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview"); + const bool use_color_management = RNA_boolean_get(op->ptr, "save_as_render"); - /* image template */ - RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->im_format, &imf_ptr); - uiTemplateImageSettings(layout, &imf_ptr, false); + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); /* main draw call */ uiDefAutoButsRNA( layout, op->ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false); + uiItemS(layout); + + /* image template */ + RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->im_format, &imf_ptr); + uiTemplateImageSettings(layout, &imf_ptr, use_color_management); + /* multiview template */ if (is_multiview) { uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr); diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index a336cc1770a..7cf2c02e657 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -53,6 +53,7 @@ bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace); bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace); bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace); bool IMB_colormanagement_space_name_is_data(const char *name); +bool IMB_colormanagement_space_name_is_scene_linear(const char *name); /** * Convert a float RGB triplet to the correct luminance weighted average. diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 8624a7866b6..15a586ea762 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -1394,6 +1394,12 @@ bool IMB_colormanagement_space_name_is_data(const char *name) return (colorspace && colorspace->is_data); } +bool IMB_colormanagement_space_name_is_scene_linear(const char *name) +{ + ColorSpace *colorspace = colormanage_colorspace_get_named(name); + return (colorspace && IMB_colormanagement_space_is_scene_linear(colorspace)); +} + const float *IMB_colormanagement_get_xyz_to_rgb() { return &imbuf_xyz_to_rgb[0][0]; @@ -2444,9 +2450,13 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID); } - const bool do_colormanagement = save_as_render && (is_movie || !requires_linear_float); + const bool do_colormanagement_display = save_as_render && (is_movie || !requires_linear_float); + const bool do_colormanagement_linear = save_as_render && requires_linear_float && + imf->linear_colorspace_settings.name[0] && + !IMB_colormanagement_space_name_is_scene_linear( + imf->linear_colorspace_settings.name); - if (do_colormanagement || do_alpha_under) { + if (do_colormanagement_display || do_colormanagement_linear || do_alpha_under) { if (allocate_result) { colormanaged_ibuf = IMB_dupImBuf(ibuf); } @@ -2499,7 +2509,8 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, } } - if (do_colormanagement) { + if (do_colormanagement_display) { + /* Color management with display and view transform. */ bool make_byte = false; /* for proper check whether byte buffer is required by a format or not @@ -2532,6 +2543,27 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, &imf->view_settings, &imf->display_settings); } } + else if (do_colormanagement_linear) { + /* Color management transform to another linear color space. */ + if (!colormanaged_ibuf->rect_float) { + IMB_float_from_rect(colormanaged_ibuf); + imb_freerectImBuf(colormanaged_ibuf); + } + + if (colormanaged_ibuf->rect_float) { + const char *from_colorspace = (ibuf->float_colorspace) ? ibuf->float_colorspace->name : + global_role_scene_linear; + const char *to_colorspace = imf->linear_colorspace_settings.name; + + IMB_colormanagement_transform(colormanaged_ibuf->rect_float, + colormanaged_ibuf->x, + colormanaged_ibuf->y, + colormanaged_ibuf->channels, + from_colorspace, + to_colorspace, + false); + } + } if (colormanaged_ibuf != ibuf) { IMB_metadata_copy(colormanaged_ibuf, ibuf); diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index be8f9f938a3..24c120ae860 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -429,6 +429,8 @@ typedef struct ImageFormatData { Stereo3dFormat stereo3d_format; /* color management */ + char color_management; + char _pad1[7]; ColorManagedViewSettings view_settings; ColorManagedDisplaySettings display_settings; ColorManagedColorspaceSettings linear_colorspace_settings; @@ -527,6 +529,10 @@ enum { R_IMF_TIFF_CODEC_NONE = 3, }; +/** #ImageFormatData.color_management */ +#define R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE 0 +#define R_IMF_COLOR_MANAGEMENT_OVERRIDE 1 + typedef struct BakeData { struct ImageFormatData im_format; diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 373aec975c2..840674c7bc6 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -605,6 +605,11 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain, { ID *id = ptr->owner_id; + if (!id) { + /* Happens for color space settings on operators. */ + return; + } + if (GS(id->name) == ID_IM) { Image *ima = (Image *)id; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 04afcd61717..e056ab7377c 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -20,6 +20,7 @@ #include "DNA_view3d_types.h" #include "DNA_world_types.h" +#include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" #include "BLI_listbase.h" @@ -29,6 +30,7 @@ #include "BKE_armature.h" #include "BKE_editmesh.h" +#include "BKE_idtype.h" #include "BKE_paint.h" #include "BKE_volume.h" @@ -1440,6 +1442,35 @@ static const EnumPropertyItem *rna_ImageFormatSettings_exr_codec_itemf(bContext } # endif + +static bool rna_ImageFormatSettings_has_linear_colorspace_get(PointerRNA *ptr) +{ + ImageFormatData *imf = (ImageFormatData *)ptr->data; + return BKE_imtype_requires_linear_float(imf->imtype); +} + +static void rna_ImageFormatSettings_color_management_set(PointerRNA *ptr, int value) +{ + ImageFormatData *imf = (ImageFormatData *)ptr->data; + + if (imf->color_management != value) { + imf->color_management = value; + + /* Copy from scene when enabling override. */ + if (imf->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) { + ID *owner_id = ptr->owner_id; + if (owner_id && GS(owner_id->name) == ID_NT) { + /* For compositing nodes, find the corresponding scene. */ + const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(owner_id); + owner_id = type_info->owner_get(G_MAIN, owner_id); + } + if (owner_id && GS(owner_id->name) == ID_SCE) { + BKE_image_format_color_management_copy_from_scene(imf, (Scene *)owner_id); + } + } + } +} + static int rna_SceneRender_file_ext_length(PointerRNA *ptr) { RenderData *rd = (RenderData *)ptr->data; @@ -5458,6 +5489,12 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna) }; # endif + static const EnumPropertyItem color_management_items[] = { + {R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE, "FOLLOW_SCENE", 0, "Follow Scene", ""}, + {R_IMF_COLOR_MANAGEMENT_OVERRIDE, "OVERRIDE", 0, "Override", ""}, + {0, NULL, 0, NULL, NULL}, + }; + StructRNA *srna; PropertyRNA *prop; @@ -5616,17 +5653,32 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3D"); /* color management */ + prop = RNA_def_property(srna, "color_management", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, color_management_items); + RNA_def_property_ui_text( + prop, "Color Management", "Which color management settings to use for file saving"); + RNA_def_property_enum_funcs(prop, NULL, "rna_ImageFormatSettings_color_management_set", NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + prop = RNA_def_property(srna, "view_settings", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "view_settings"); RNA_def_property_struct_type(prop, "ColorManagedViewSettings"); RNA_def_property_ui_text( prop, "View Settings", "Color management settings applied on image before saving"); prop = RNA_def_property(srna, "display_settings", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "display_settings"); RNA_def_property_struct_type(prop, "ColorManagedDisplaySettings"); RNA_def_property_ui_text( prop, "Display Settings", "Settings of device saved image would be displayed on"); + + prop = RNA_def_property(srna, "linear_colorspace_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings"); + RNA_def_property_ui_text(prop, "Color Space Settings", "Output color space settings"); + + prop = RNA_def_property(srna, "has_linear_colorspace", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_ImageFormatSettings_has_linear_colorspace_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text( + prop, "Has Linear Color Space", "File format expects linear color space"); } static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) diff --git a/source/blender/nodes/composite/nodes/node_composite_output_file.cc b/source/blender/nodes/composite/nodes/node_composite_output_file.cc index 28de1f48b79..1fd6e62b4c5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_output_file.cc +++ b/source/blender/nodes/composite/nodes/node_composite_output_file.cc @@ -303,7 +303,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0; node_composit_buts_file_output(layout, C, ptr); - uiTemplateImageSettings(layout, &imfptr, false); + uiTemplateImageSettings(layout, &imfptr, true); /* disable stereo output for multilayer, too much work for something that no one will use */ /* if someone asks for that we can implement it */ @@ -422,12 +422,16 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi ICON_NONE); } - col = uiLayoutColumn(layout, false); - uiLayoutSetActive(col, use_node_format == false); - uiTemplateImageSettings(col, &imfptr, false); + if (!use_node_format) { + const bool use_color_management = RNA_boolean_get(&active_input_ptr, "save_as_render"); - if (is_multiview) { - uiTemplateImageFormatViews(layout, &imfptr, nullptr); + col = uiLayoutColumn(layout, false); + uiTemplateImageSettings(col, &imfptr, use_color_management); + + if (is_multiview) { + col = uiLayoutColumn(layout, false); + uiTemplateImageFormatViews(col, &imfptr, nullptr); + } } } } diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c index 3ea708a5b72..ea7fa961f0d 100644 --- a/source/blender/render/intern/render_result.c +++ b/source/blender/render/intern/render_result.c @@ -993,7 +993,7 @@ void render_result_exr_file_cache_write(Render *re) render_result_exr_file_cache_path(re->scene, root, str); printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str); - BKE_image_render_write_exr(NULL, rr, str, NULL, NULL, -1); + BKE_image_render_write_exr(NULL, rr, str, NULL, true, NULL, -1); } bool render_result_exr_file_cache_read(Render *re) |