Fix #32603: Multi-Layer EXR files can't be color managed
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 20 Sep 2012 10:07:49 +0000 (10:07 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 20 Sep 2012 10:07:49 +0000 (10:07 +0000)
Issue was caused by completely different way how multi-layer EXRs are loading,
they're bypassing general image buffer loading functions.

Solved by running color space transformation on render result construction
from multi-layer EXR image.

Also fixed issue with wrong display buffer computing for buffers with less
than 4 channels. Issues were:

- Display buffer is always expected to be RGBA
- OpenColorIO can not apply color space transformations on non-{RGB, RGBA}
  pixels.

source/blender/blenkernel/intern/image.c
source/blender/imbuf/intern/colormanagement.c
source/blender/render/extern/include/RE_pipeline.h
source/blender/render/intern/include/render_result.h
source/blender/render/intern/source/pipeline.c
source/blender/render/intern/source/render_result.c

index 7146c48cd2f688b19f44ec0da3ea4d0574280c9a..b0fdbba2aa90a896445a6769ba5a5fe0deaf8388 100644 (file)
@@ -2213,8 +2213,10 @@ void BKE_image_backup_render(Scene *scene, Image *ima)
 /* in that case we have to build a render-result */
 static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
 {
+       const char *colorspace = ima->colorspace_settings.name;
+       int predivide = ima->flag & IMA_CM_PREDIVIDE;
 
-       ima->rr = RE_MultilayerConvert(ibuf->userdata, ibuf->x, ibuf->y);
+       ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
 
 #ifdef WITH_OPENEXR
        IMB_exr_close(ibuf->userdata);
index 310448074fb86e1ef4856b3c6d23314c6bf98e0a..4843c9b2b6cd496e18da4cc01d99b5be124b9af4 100644 (file)
@@ -68,7 +68,8 @@
 
 /*********************** Global declarations *************************/
 
-#define MAX_COLORSPACE_NAME 64
+#define MAX_COLORSPACE_NAME     64
+#define DISPLAY_BUFFER_CHANNELS 4
 
 /* ** list of all supported color spaces, displays and views */
 static char global_role_scene_linear[MAX_COLORSPACE_NAME];
@@ -329,8 +330,7 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV
                ColormnaageCacheData *cache_data;
 
                BLI_assert(cache_ibuf->x == ibuf->x &&
-                          cache_ibuf->y == ibuf->y &&
-                          cache_ibuf->channels == ibuf->channels);
+                          cache_ibuf->y == ibuf->y);
 
                /* only buffers with different color space conversions are being stored
                 * in cache separately. buffer which were used only different exposure/gamma
@@ -1089,6 +1089,7 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l
        int is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
 
        int offset = channels * start_line * ibuf->x;
+       int display_buffer_byte_offset = DISPLAY_BUFFER_CHANNELS * start_line * ibuf->x;
 
        memset(handle, 0, sizeof(DisplayBufferThread));
 
@@ -1104,7 +1105,7 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l
                handle->display_buffer = init_data->display_buffer + offset;
 
        if (init_data->display_buffer_byte)
-               handle->display_buffer_byte = init_data->display_buffer_byte + offset;
+               handle->display_buffer_byte = init_data->display_buffer_byte + display_buffer_byte_offset;
 
        handle->width = ibuf->x;
 
@@ -1655,7 +1656,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
                        return display_buffer;
                }
 
-               buffer_size = ibuf->channels * ibuf->x * ibuf->y * sizeof(float);
+               buffer_size = DISPLAY_BUFFER_CHANNELS * ibuf->x * ibuf->y * sizeof(float);
                display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
 
                colormanage_display_buffer_process(ibuf, display_buffer, applied_view_settings, display_settings);
@@ -1700,7 +1701,7 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *li
                                         const ColorManagedDisplaySettings *display_settings, int predivide)
 {
        if (global_tot_display == 0 || global_tot_view == 0) {
-               IMB_buffer_byte_from_float(display_buffer, linear_buffer, 4, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, FALSE,
+               IMB_buffer_byte_from_float(display_buffer, linear_buffer, channels, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, FALSE,
                                           width, height, width, width);
        }
        else {
@@ -2351,7 +2352,7 @@ void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, flo
                }
        }
 
-       if (cm_processor->processor) {
+       if (cm_processor->processor && channels >= 3) {
                PackedImageDesc *img;
 
                /* apply OCIO processor */
index b43824d6d5e46ef984ef0ef58585bde6b351979a..c7a8bfeec1d7984d0e680947b46897742fa3ad96 100644 (file)
@@ -225,7 +225,7 @@ void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene
 
 int RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode);
 int RE_WriteRenderResult(struct ReportList *reports, RenderResult *rr, const char *filename, int compress);
-struct RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty);
+struct RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, int predivide, int rectx, int recty);
 
 extern const float default_envmap_layout[];
 int RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]);
index 999fb24ba32cbc0348db46396a1a547c5d0a4205..5d61417cbaf522f37f50688ca40a7def26a60e44 100644 (file)
@@ -57,7 +57,7 @@ struct RenderResult *render_result_new(struct Render *re,
 struct RenderResult *render_result_new_full_sample(struct Render *re,
        struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers);
 
-struct RenderResult *render_result_new_from_exr(void *exrhandle, int rectx, int recty);
+struct RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, int predivide, int rectx, int recty);
 
 /* Merge */
 
index 4a1674b8bcadb77a4e21a16acdc5f00a6ee98037..d22e8f95e0186a1209c31e14dcfab969bfc06fc6 100644 (file)
@@ -203,9 +203,9 @@ RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name)
        }
 }
 
-RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty)
+RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, int predivide, int rectx, int recty)
 {
-       return render_result_new_from_exr(exrhandle, rectx, recty);
+       return render_result_new_from_exr(exrhandle, colorspace, predivide, rectx, recty);
 }
 
 RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
index 2d680bf2e81cf9f5e2c6dbabe90eb4e0af6e78e7..0bac26e7e3cb0537370da3ed7bca84c4529db896 100644 (file)
@@ -627,12 +627,13 @@ static void ml_addpass_cb(void *UNUSED(base), void *lay, const char *str, float
 }
 
 /* from imbuf, if a handle was returned we convert this to render result */
-RenderResult *render_result_new_from_exr(void *exrhandle, int rectx, int recty)
+RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, int predivide, int rectx, int recty)
 {
        RenderResult *rr = MEM_callocN(sizeof(RenderResult), __func__);
        RenderLayer *rl;
        RenderPass *rpass;
-       
+       const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
+
        rr->rectx = rectx;
        rr->recty = recty;
        
@@ -645,6 +646,11 @@ RenderResult *render_result_new_from_exr(void *exrhandle, int rectx, int recty)
                for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
                        rpass->rectx = rectx;
                        rpass->recty = recty;
+
+                       if (rpass->channels >= 3) {
+                               IMB_colormanagement_transform(rpass->rect, rpass->rectx, rpass->recty, rpass->channels,
+                                                             colorspace, to_colorspace, predivide);
+                       }
                }
        }