[Bf-blender-cvs] [5baa3ecda66] master: Color Management: various improvements and fixes for image saving

Brecht Van Lommel noreply at git.blender.org
Fri May 13 17:56:15 CEST 2022


Commit: 5baa3ecda66337c0584f0bc6c6e7af0a6c0f6320
Author: Brecht Van Lommel
Date:   Fri May 13 16:03:26 2022 +0200
Branches: master
https://developer.blender.org/rB5baa3ecda66337c0584f0bc6c6e7af0a6c0f6320

Color Management: various improvements and fixes for image saving

* Respect the image file color space setitng for saving in various cases where
  it was previously ignored. Previously it would often use the sRGB or Linear
  color space even when not selected.
* For the Save As operator, add a Color Space option in the file browser to
  choose the color space of the file. Previously this was chosen automatically,
  now it's possible to e.g. resave a Linear image as Linear ACES.
* When changing the file format, the colorspace is automatically changed to an
  appropriate color space for the file format. This already happened before, but
  there was no visibility or control in the operator settings for this.
* Don't change color space when using the Save operator to save over the same
  file.
* Fix missing color space conversion for 16 bit PNGs, where it assumed wrongly
  assumed ibuf->rect would be used for saving. Add BKE_image_format_is_byte to
  more accurately test this.

Fixes T74610

Ref T68926

Differential Revision: https://developer.blender.org/D14899

===================================================================

M	source/blender/blenkernel/BKE_image_format.h
M	source/blender/blenkernel/BKE_image_save.h
M	source/blender/blenkernel/intern/image_format.cc
M	source/blender/blenkernel/intern/image_save.cc
M	source/blender/compositor/operations/COM_OutputFileOperation.cc
M	source/blender/editors/space_image/image_ops.c
M	source/blender/imbuf/intern/colormanagement.c

===================================================================

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");
 
 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list