Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_image_format.h2
-rw-r--r--source/blender/blenkernel/BKE_image_save.h5
-rw-r--r--source/blender/blenkernel/intern/image_format.cc5
-rw-r--r--source/blender/blenkernel/intern/image_save.cc82
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cc6
-rw-r--r--source/blender/editors/space_image/image_ops.c19
-rw-r--r--source/blender/imbuf/intern/colormanagement.c209
7 files changed, 226 insertions, 102 deletions
diff --git a/source/blender/blenkernel/BKE_image_format.h b/source/blender/blenkernel/BKE_image_format.h
index 633af54ea4f..6a03d1d8df5 100644
--- a/source/blender/blenkernel/BKE_image_format.h
+++ b/source/blender/blenkernel/BKE_image_format.h
@@ -76,6 +76,8 @@ char BKE_imtype_from_arg(const char *arg);
void BKE_image_format_from_imbuf(struct ImageFormatData *im_format, const struct ImBuf *imbuf);
void BKE_image_format_to_imbuf(struct ImBuf *ibuf, const struct ImageFormatData *imf);
+bool BKE_image_format_is_byte(const struct ImageFormatData *imf);
+
/* Color Management */
void BKE_image_format_color_management_copy(struct ImageFormatData *imf,
diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h
index f5695eb11a4..673a7dffb82 100644
--- a/source/blender/blenkernel/BKE_image_save.h
+++ b/source/blender/blenkernel/BKE_image_save.h
@@ -35,6 +35,10 @@ typedef struct ImageSaveOptions {
bool save_copy;
bool save_as_render;
bool do_newpath;
+
+ /* Keep track of previous values for auto updates in UI. */
+ bool prev_save_as_render;
+ int prev_imtype;
} ImageSaveOptions;
bool BKE_image_save_options_init(ImageSaveOptions *opts,
@@ -44,6 +48,7 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
struct ImageUser *iuser,
const bool guess_path,
const bool save_as_render);
+void BKE_image_save_options_update(struct ImageSaveOptions *opts, struct Image *ima);
void BKE_image_save_options_free(struct ImageSaveOptions *opts);
bool BKE_image_save(struct ReportList *reports,
diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc
index 30be1fdaba7..57763e1670f 100644
--- a/source/blender/blenkernel/intern/image_format.cc
+++ b/source/blender/blenkernel/intern/image_format.cc
@@ -911,6 +911,11 @@ void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
im_format->planes = imbuf->planes;
}
+bool BKE_image_format_is_byte(const ImageFormatData *imf)
+{
+ return (imf->depth == R_IMF_CHAN_DEPTH_8) && (BKE_imtype_valid_depths(imf->imtype) & imf->depth);
+}
+
/* Color Management */
void BKE_image_format_color_management_copy(ImageFormatData *imf, const ImageFormatData *imf_src)
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index 0fd997c3a9b..106384643df 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -121,9 +121,16 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
opts->im_format.stereo3d_format = *ima->stereo3d_format;
opts->im_format.views_format = ima->views_format;
+ /* Render output: colorspace from render settings. */
BKE_image_format_color_management_copy_from_scene(&opts->im_format, scene);
}
+ /* Default to saving in the same colorspace as the image setting. */
+ if (!save_as_render) {
+ BKE_color_managed_colorspace_settings_copy(&opts->im_format.linear_colorspace_settings,
+ &ima->colorspace_settings);
+ }
+
opts->im_format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE;
if (ima->source == IMA_SRC_TILED) {
@@ -177,11 +184,57 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
}
}
+ /* Copy for detecting UI changes. */
+ opts->prev_save_as_render = opts->save_as_render;
+ opts->prev_imtype = opts->im_format.imtype;
+
BKE_image_release_ibuf(ima, ibuf, lock);
return (ibuf != NULL);
}
+void BKE_image_save_options_update(ImageSaveOptions *opts, Image *image)
+{
+ /* Auto update color space when changing save as render and file type. */
+ if (opts->save_as_render) {
+ if (!opts->prev_save_as_render) {
+ if (ELEM(image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
+ BKE_image_format_init_for_write(&opts->im_format, opts->scene, NULL);
+ }
+ else {
+ BKE_image_format_color_management_copy_from_scene(&opts->im_format, opts->scene);
+ }
+ }
+ }
+ else {
+ if (opts->prev_save_as_render) {
+ /* Copy colorspace from image settings. */
+ BKE_color_managed_colorspace_settings_copy(&opts->im_format.linear_colorspace_settings,
+ &image->colorspace_settings);
+ }
+ else if (opts->im_format.imtype != opts->prev_imtype) {
+ const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype);
+
+ /* TODO: detect if the colorspace is linear, not just equal to scene linear. */
+ const bool is_linear = IMB_colormanagement_space_name_is_scene_linear(
+ opts->im_format.linear_colorspace_settings.name);
+
+ /* If changing to a linear float or byte format, ensure we have a compatible color space. */
+ if (linear_float_output && !is_linear) {
+ STRNCPY(opts->im_format.linear_colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_FLOAT));
+ }
+ else if (!linear_float_output && is_linear) {
+ STRNCPY(opts->im_format.linear_colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE));
+ }
+ }
+ }
+
+ opts->prev_save_as_render = opts->save_as_render;
+ opts->prev_imtype = opts->im_format.imtype;
+}
+
void BKE_image_save_options_free(ImageSaveOptions *opts)
{
BKE_image_format_free(&opts->im_format);
@@ -243,12 +296,17 @@ static void image_save_post(ReportList *reports,
BLI_path_rel(ima->filepath, relbase); /* only after saving */
}
- ColorManagedColorspaceSettings old_colorspace_settings;
- BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings, &ima->colorspace_settings);
- IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
- if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
- &ima->colorspace_settings)) {
- *r_colorspace_changed = true;
+ /* Update image file color space when saving to another color space. */
+ const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype);
+
+ if (!opts->save_as_render || linear_float_output) {
+ if (opts->im_format.linear_colorspace_settings.name[0] &&
+ !BKE_color_managed_colorspace_settings_equals(
+ &ima->colorspace_settings, &opts->im_format.linear_colorspace_settings)) {
+ BKE_color_managed_colorspace_settings_copy(&ima->colorspace_settings,
+ &opts->im_format.linear_colorspace_settings);
+ *r_colorspace_changed = true;
+ }
}
}
@@ -314,12 +372,12 @@ static bool image_save_single(ReportList *reports,
/* we need renderresult for exr and rendered multiview */
rr = BKE_image_acquire_renderresult(opts->scene, ima);
- bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 :
- BLI_listbase_count_at_most(&ima->views, 2) < 2;
- bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
- RE_HasFloatPixels(rr);
- bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
- int layer = (iuser && !is_multilayer) ? iuser->layer : -1;
+ const bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 :
+ BLI_listbase_count_at_most(&ima->views, 2) < 2;
+ const bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
+ RE_HasFloatPixels(rr);
+ const bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
+ const int layer = (iuser && !is_multilayer) ? iuser->layer : -1;
/* error handling */
if (rr == nullptr) {
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc
index 372e0736cd2..49de275c256 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc
@@ -219,6 +219,12 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(const Scene *scene,
image_input_ = nullptr;
BKE_image_format_init_for_write(&format_, scene, format);
+ if (!save_as_render) {
+ /* If not saving as render, stop IMB_colormanagement_imbuf_for_write using this
+ * colorspace for conversion. */
+ format_.linear_colorspace_settings.name[0] = '\0';
+ }
+
BLI_strncpy(path_, path, sizeof(path_));
view_name_ = view_name;
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 12ff821f7aa..20f6bae3e52 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1775,6 +1775,7 @@ static int image_save_as_exec(bContext *C, wmOperator *op)
if (op->customdata) {
isd = op->customdata;
image_save_options_from_op(bmain, &isd->opts, op);
+ BKE_image_save_options_update(&isd->opts, isd->image);
}
else {
isd = image_save_as_init(C, op);
@@ -1794,9 +1795,14 @@ static int image_save_as_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op)
+static bool image_save_as_check(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
ImageSaveData *isd = op->customdata;
+
+ image_save_options_from_op(bmain, &isd->opts, op);
+ BKE_image_save_options_update(&isd->opts, isd->image);
+
return WM_operator_filesel_ensure_ext_imtype(op, &isd->opts.im_format);
}
@@ -1839,7 +1845,7 @@ 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");
+ const bool save_as_render = RNA_boolean_get(op->ptr, "save_as_render");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -1852,7 +1858,14 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
/* image template */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->opts.im_format, &imf_ptr);
- uiTemplateImageSettings(layout, &imf_ptr, use_color_management);
+ uiTemplateImageSettings(layout, &imf_ptr, save_as_render);
+
+ if (!save_as_render) {
+ PointerRNA linear_settings_ptr = RNA_pointer_get(&imf_ptr, "linear_colorspace_settings");
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemS(col);
+ uiItemR(col, &linear_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE);
+ }
/* multiview template */
if (is_multiview) {
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 53aa74edc61..1613595148b 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -2445,68 +2445,77 @@ void IMB_colormanagement_imbuf_make_display_space(
colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
}
+static ImBuf *imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool allocate_result)
+{
+ if (colormanaged_ibuf != ibuf) {
+ /* Is already an editable copy. */
+ return colormanaged_ibuf;
+ }
+
+ if (allocate_result) {
+ /* Copy full image buffer. */
+ colormanaged_ibuf = IMB_dupImBuf(ibuf);
+ IMB_metadata_copy(colormanaged_ibuf, ibuf);
+ return colormanaged_ibuf;
+ }
+ else {
+ /* Render pipeline is constructing image buffer itself,
+ * but it's re-using byte and float buffers from render result make copy of this buffers
+ * here sine this buffers would be transformed to other color space here. */
+ if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
+ ibuf->rect = MEM_dupallocN(ibuf->rect);
+ ibuf->mall |= IB_rect;
+ }
+
+ if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
+ ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
+ ibuf->mall |= IB_rectfloat;
+ }
+
+ return ibuf;
+ }
+}
+
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
bool save_as_render,
bool allocate_result,
const ImageFormatData *image_format)
{
ImBuf *colormanaged_ibuf = ibuf;
- const bool is_movie = BKE_imtype_is_movie(image_format->imtype);
- const bool requires_linear_float = BKE_imtype_requires_linear_float(image_format->imtype);
- const bool do_alpha_under = image_format->planes != R_IMF_PLANES_RGBA;
+ /* Update byte buffer if exists but invalid. */
if (ibuf->rect_float && ibuf->rect &&
(ibuf->userflags & (IB_DISPLAY_BUFFER_INVALID | IB_RECT_INVALID)) != 0) {
IMB_rect_from_float(ibuf);
ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID);
}
- const bool do_colormanagement_display = save_as_render && (is_movie || !requires_linear_float);
- const bool do_colormanagement_linear = save_as_render && requires_linear_float &&
- image_format->linear_colorspace_settings.name[0] &&
- !IMB_colormanagement_space_name_is_scene_linear(
- image_format->linear_colorspace_settings.name);
-
- if (do_colormanagement_display || do_colormanagement_linear || do_alpha_under) {
- if (allocate_result) {
- colormanaged_ibuf = IMB_dupImBuf(ibuf);
- }
- else {
- /* Render pipeline is constructing image buffer itself,
- * but it's re-using byte and float buffers from render result make copy of this buffers
- * here sine this buffers would be transformed to other color space here.
- */
+ /* Detect if we are writing to a file format that needs a linear float buffer. */
+ const bool linear_float_output = BKE_imtype_requires_linear_float(image_format->imtype);
- if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
- ibuf->rect = MEM_dupallocN(ibuf->rect);
- ibuf->mall |= IB_rect;
- }
+ /* Detect if we are writing output a byte buffer, which we would need to create
+ * with color management conversions applied. This may be for either applying the
+ * display transform for renders, or a user specified color space for the file. */
+ const bool byte_output = BKE_image_format_is_byte(image_format);
- if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
- ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
- ibuf->mall |= IB_rectfloat;
- }
- }
- }
+ BLI_assert(!(byte_output && linear_float_output));
- /* If we're saving from RGBA to RGB buffer then it's not
- * so much useful to just ignore alpha -- it leads to bad
- * artifacts especially when saving byte images.
- *
- * What we do here is we're overlaying our image on top of
- * background color (which is currently black).
+ /* If we're saving from RGBA to RGB buffer then it's not so much useful to just ignore alpha --
+ * it leads to bad artifacts especially when saving byte images.
*
- * This is quite much the same as what Gimp does and it
- * seems to be what artists expects from saving.
+ * What we do here is we're overlaying our image on top of background color (which is currently
+ * black). This is quite much the same as what Gimp does and it seems to be what artists expects
+ * from saving.
*
- * Do a conversion here, so image format writers could
- * happily assume all the alpha tricks were made already.
- * helps keep things locally here, not spreading it to
- * all possible image writers we've got.
+ * Do a conversion here, so image format writers could happily assume all the alpha tricks were
+ * made already. helps keep things locally here, not spreading it to all possible image writers
+ * we've got.
*/
- if (do_alpha_under) {
+ if (image_format->planes != R_IMF_PLANES_RGBA) {
float color[3] = {0, 0, 0};
+ colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
+
if (colormanaged_ibuf->rect_float && colormanaged_ibuf->channels == 4) {
IMB_alpha_under_color_float(
colormanaged_ibuf->rect_float, colormanaged_ibuf->x, colormanaged_ibuf->y, color);
@@ -2520,69 +2529,95 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
}
}
- if (do_colormanagement_display) {
- /* Color management with display and view transform. */
- bool make_byte = false;
+ if (save_as_render && !linear_float_output) {
+ /* Render output: perform conversion to display space using view transform. */
+ colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
- /* for proper check whether byte buffer is required by a format or not
- * should be pretty safe since this image buffer is supposed to be used for
- * saving only and ftype would be overwritten a bit later by BKE_imbuf_write
- */
- colormanaged_ibuf->ftype = BKE_imtype_to_ftype(image_format->imtype,
- &colormanaged_ibuf->foptions);
-
- /* if file format isn't able to handle float buffer itself,
- * we need to allocate byte buffer and store color managed
- * image there
- */
- const ImFileType *type = IMB_file_type_from_ibuf(colormanaged_ibuf);
- if (type != NULL) {
- if ((type->save != NULL) && (type->flag & IM_FTYPE_FLOAT) == 0) {
- make_byte = true;
- }
- }
-
- /* perform color space conversions */
colormanagement_imbuf_make_display_space(colormanaged_ibuf,
&image_format->view_settings,
&image_format->display_settings,
- make_byte);
+ byte_output);
if (colormanaged_ibuf->rect_float) {
- /* float buffer isn't linear anymore,
+ /* Float buffer isn't linear anymore,
* image format write callback should check for this flag and assume
- * no space conversion should happen if ibuf->float_colorspace != NULL
- */
+ * no space conversion should happen if ibuf->float_colorspace != NULL. */
colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(
&image_format->view_settings, &image_format->display_settings);
+ if (byte_output) {
+ colormanaged_ibuf->rect_colorspace = colormanaged_ibuf->float_colorspace;
+ }
}
}
- 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);
+ else {
+ /* Linear render or regular file output: conversion between two color spaces. */
+
+ /* Detect which color space we need to convert between. */
+ const char *from_colorspace = (ibuf->rect_float && !(byte_output && ibuf->rect)) ?
+ /* From float buffer. */
+ (ibuf->float_colorspace) ? ibuf->float_colorspace->name :
+ global_role_scene_linear :
+ /* From byte buffer. */
+ (ibuf->rect_colorspace) ? ibuf->rect_colorspace->name :
+ global_role_default_byte;
+
+ const char *to_colorspace = image_format->linear_colorspace_settings.name;
+
+ /* TODO: can we check with OCIO if color spaces are the same but have different names? */
+ if (to_colorspace[0] == '\0' || STREQ(from_colorspace, to_colorspace)) {
+ /* No conversion needed, but may still need to allocate byte buffer for output. */
+ if (byte_output && !ibuf->rect) {
+ ibuf->rect_colorspace = ibuf->float_colorspace;
+ IMB_rect_from_float(ibuf);
+ }
}
+ else {
+ /* Color space conversion needed. */
+ colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
+
+ if (byte_output) {
+ colormanaged_ibuf->rect_colorspace = colormanage_colorspace_get_named(to_colorspace);
+
+ if (colormanaged_ibuf->rect) {
+ /* Byte to byte. */
+ IMB_colormanagement_transform_byte_threaded((unsigned char *)colormanaged_ibuf->rect,
+ colormanaged_ibuf->x,
+ colormanaged_ibuf->y,
+ colormanaged_ibuf->channels,
+ from_colorspace,
+ to_colorspace);
+ }
+ else {
+ /* Float to byte. */
+ IMB_rect_from_float(colormanaged_ibuf);
+ }
+ }
+ else {
+ if (!colormanaged_ibuf->rect_float) {
+ /* Byte to 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 = image_format->linear_colorspace_settings.name;
+ /* This conversion always goes to scene linear. */
+ from_colorspace = global_role_scene_linear;
+ }
- IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
- colormanaged_ibuf->x,
- colormanaged_ibuf->y,
- colormanaged_ibuf->channels,
- from_colorspace,
- to_colorspace,
- false);
+ if (colormanaged_ibuf->rect_float) {
+ /* Float to float. */
+ IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
+ colormanaged_ibuf->x,
+ colormanaged_ibuf->y,
+ colormanaged_ibuf->channels,
+ from_colorspace,
+ to_colorspace,
+ false);
+
+ colormanaged_ibuf->float_colorspace = colormanage_colorspace_get_named(to_colorspace);
+ }
+ }
}
}
- if (colormanaged_ibuf != ibuf) {
- IMB_metadata_copy(colormanaged_ibuf, ibuf);
- }
-
return colormanaged_ibuf;
}