Color Management: made OpenColorIO transformations aware of color unpremultiply
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 5 Sep 2012 13:58:01 +0000 (13:58 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 5 Sep 2012 13:58:01 +0000 (13:58 +0000)
Mainly behaves in the same way as legacy color transformation, but it'll
give different result on over and under exposured areas.

Not sure if it's indeed issue -- seems this behaves crappy in both of
current stable release and OCIO branch.

intern/opencolorio/ocio_capi.cpp
intern/opencolorio/ocio_capi.h
source/blender/editors/space_image/space_image.c
source/blender/imbuf/IMB_colormanagement.h
source/blender/imbuf/intern/colormanagement.c

index 15ef0dd25e9b057ccb4383de00e0a5664094cc8b..6fec1185bd56ff9c983e20f9ee5e38aca45e9974 100644 (file)
@@ -304,6 +304,34 @@ void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img)
        }
 }
 
+void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img)
+{
+       try {
+               int channels = img->getNumChannels();
+
+               if (channels == 4) {
+                       float *pixels = img->getData();
+
+                       int width = img->getWidth();
+                       int height = img->getHeight();
+
+                       for (int y = 0; y < height; y++) {
+                               for (int x = 0; x < width; x++) {
+                                       float *pixel = pixels + 4 * (y * width + x);
+
+                                       OCIO_processorApplyRGBA_predivide(processor, pixel);
+                               }
+                       }
+               }
+               else {
+                       (*processor)->apply(*img);
+               }
+       }
+       catch (Exception &exception) {
+               OCIO_reportException(exception);
+       }
+}
+
 void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel)
 {
        (*processor)->applyRGB(pixel);
@@ -314,6 +342,29 @@ void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel)
        (*processor)->applyRGBA(pixel);
 }
 
+void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel)
+{
+       if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
+               (*processor)->applyRGBA(pixel);
+       }
+       else {
+               float alpha, inv_alpha;
+
+               alpha = pixel[3];
+               inv_alpha = 1.0f / alpha;
+
+               pixel[0] *= inv_alpha;
+               pixel[1] *= inv_alpha;
+               pixel[2] *= inv_alpha;
+
+               (*processor)->applyRGBA(pixel);
+
+               pixel[0] *= alpha;
+               pixel[1] *= alpha;
+               pixel[2] *= alpha;
+       }
+}
+
 void OCIO_processorRelease(ConstProcessorRcPtr *p)
 {
        delete p;
index 1af77ad41ea0b20d0933f58fa859f42e23a919c3..c3830f3fc72ef9ba0a0fb97795459c72f50549e7 100644 (file)
@@ -83,8 +83,10 @@ ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config,
 ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform);
 
 void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img);
+void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img);
 void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel);
 void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel);
+void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel);
 
 void OCIO_processorRelease(ConstProcessorRcPtr *p);
 
index cff1f987da6c4d004fe514236a23e4b788fcf480..439f6a49c7fd4af9993f20cdf42667ad6d4dc518 100644 (file)
@@ -443,6 +443,7 @@ static void image_listener(ScrArea *sa, wmNotifier *wmn)
                                        break;
                                case ND_MODE:
                                case ND_RENDER_RESULT:
+                               case ND_RENDER_OPTIONS:
                                case ND_COMPO_RESULT:
                                        if (ED_space_image_show_render(sima))
                                                image_scopes_tag_refresh(sa);
index 106ed2f6ea1c1d32e1e3c0427b0f619f350550d1..2df67b6912cf43501b1367fe1df31cc92fcc3244 100644 (file)
@@ -59,7 +59,8 @@ void IMB_colormanagement_validate_settings(struct ColorManagedDisplaySettings *d
 
 /* ** Color space transformation functions ** */
 void IMB_colormanagement_colorspace_transform(float *buffer, int width, int height, int channels,
-                                              const char *from_colorspace, const char *to_colorspace);
+                                              const char *from_colorspace, const char *to_colorspace,
+                                              int predivide);
 
 void IMB_colormanagement_pixel_to_role(float pixel[4], int role);
 void IMB_colormanagement_pixel_from_role(float pixel[4], int role);
index 5e446d8cb812ead66895089ee9b1c3317b40184d..f0b6a1bda1da3de02b2045faeacec9670b32664c 100644 (file)
@@ -176,6 +176,7 @@ typedef struct ColormanageCacheKey {
 typedef struct ColormnaageCacheData {
        float exposure;  /* exposure value cached buffer is calculated with */
        float gamma;     /* gamma value cached buffer is calculated with */
+       int predivide;   /* predivide flag of cached buffer */
 } ColormnaageCacheData;
 
 typedef struct ColormanageCache {
@@ -308,6 +309,7 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV
        ColormanageCacheKey key;
        ImBuf *cache_ibuf;
        int view_flag = 1 << (view_settings->view - 1);
+       int predivide = ibuf->flags & IB_cm_predivide;
 
        colormanage_settings_to_key(&key, view_settings, display_settings);
 
@@ -335,7 +337,8 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV
                cache_data = colormanage_cachedata_get(cache_ibuf);
 
                if (cache_data->exposure != view_settings->exposure ||
-                   cache_data->gamma != view_settings->gamma)
+                   cache_data->gamma != view_settings->gamma ||
+                       cache_data->predivide != predivide)
                {
                        *cache_handle = NULL;
 
@@ -358,6 +361,7 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting
        ImBuf *cache_ibuf;
        ColormnaageCacheData *cache_data;
        int view_flag = 1 << (view_settings->view - 1);
+       int predivide = ibuf->flags & IB_cm_predivide;
        struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf);
 
        colormanage_settings_to_key(&key, view_settings, display_settings);
@@ -376,6 +380,7 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting
        cache_data = MEM_callocN(sizeof(ColormnaageCacheData), "color manage cache imbuf data");
        cache_data->exposure = view_settings->exposure;
        cache_data->gamma = view_settings->gamma;
+       cache_data->predivide = predivide;
 
        colormanage_cachedata_set(cache_ibuf, cache_data);
 
@@ -693,7 +698,6 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle)
 
        int buffer_size = channels * width * height;
 
-       /* TODO: do we actually need to handle alpha premultiply in some way here? */
        int predivide = handle->predivide;
 
        linear_buffer = MEM_callocN(buffer_size * sizeof(float), "color conversion linear buffer");
@@ -721,7 +725,7 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle)
                memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
 
                IMB_colormanagement_colorspace_transform(linear_buffer, width, height, channels,
-                                                        from_colorspace, to_colorspace);
+                                                        from_colorspace, to_colorspace, predivide);
        }
        else {
                /* some processors would want to modify float original buffer
@@ -758,7 +762,10 @@ static void *do_display_buffer_apply_thread(void *handle_v)
        img = OCIO_createPackedImageDesc(linear_buffer, width, height, channels, sizeof(float),
                                         channels * sizeof(float), channels * sizeof(float) * width);
 
-       OCIO_processorApply(processor, img);
+       if (predivide)
+               OCIO_processorApply_predivide(processor, img);
+       else
+               OCIO_processorApply(processor, img);
 
        OCIO_packedImageDescRelease(img);
 
@@ -865,6 +872,7 @@ typedef struct ColorspaceTransformThread {
        int start_line;
        int tot_line;
        int channels;
+       int predivide;
 } ColorspaceTransformThread;
 
 typedef struct ColorspaceTransformInit {
@@ -873,6 +881,7 @@ typedef struct ColorspaceTransformInit {
        int width;
        int height;
        int channels;
+       int predivide;
 } ColorspaceTransformInitData;
 
 static void colorspace_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
@@ -882,6 +891,7 @@ static void colorspace_transform_init_handle(void *handle_v, int start_line, int
 
        int channels = init_data->channels;
        int width = init_data->width;
+       int predivide = init_data->predivide;
 
        int offset = channels * start_line * width;
 
@@ -897,10 +907,11 @@ static void colorspace_transform_init_handle(void *handle_v, int start_line, int
        handle->tot_line = tot_line;
 
        handle->channels = channels;
+       handle->predivide = predivide;
 }
 
 static void colorspace_transform_apply_threaded(float *buffer, int width, int height, int channels,
-                                                void *processor, void *(do_thread) (void *))
+                                                void *processor, int predivide, void *(do_thread) (void *))
 {
        ColorspaceTransformInitData init_data;
 
@@ -909,6 +920,7 @@ static void colorspace_transform_apply_threaded(float *buffer, int width, int he
        init_data.width = width;
        init_data.height = height;
        init_data.channels = channels;
+       init_data.predivide = predivide;
 
        IMB_processor_apply_threaded(height, sizeof(ColorspaceTransformThread), &init_data,
                                     colorspace_transform_init_handle, do_thread);
@@ -923,11 +935,15 @@ static void *do_color_space_transform_thread(void *handle_v)
        int channels = handle->channels;
        int width = handle->width;
        int height = handle->tot_line;
+       int predivide = handle->predivide;
 
        img = OCIO_createPackedImageDesc(buffer, width, height, channels, sizeof(float),
                                         channels * sizeof(float), channels * sizeof(float) * width);
 
-       OCIO_processorApply(processor, img);
+       if (predivide)
+               OCIO_processorApply_predivide(processor, img);
+       else
+               OCIO_processorApply(processor, img);
 
        OCIO_packedImageDescRelease(img);
 
@@ -947,7 +963,8 @@ static ConstProcessorRcPtr *create_colorspace_transform_processor(const char *fr
 #endif
 
 void IMB_colormanagement_colorspace_transform(float *buffer, int width, int height, int channels,
-                                              const char *from_colorspace, const char *to_colorspace)
+                                              const char *from_colorspace, const char *to_colorspace,
+                                              int predivide)
 {
 #ifdef WITH_OCIO
        ConstProcessorRcPtr *processor;
@@ -966,8 +983,8 @@ void IMB_colormanagement_colorspace_transform(float *buffer, int width, int heig
        processor = create_colorspace_transform_processor(from_colorspace, to_colorspace);
 
        if (processor) {
-               colorspace_transform_apply_threaded(buffer, width, height, channels,
-                                                   processor, do_color_space_transform_thread);
+               colorspace_transform_apply_threaded(buffer, width, height, channels, processor, predivide,
+                                                   do_color_space_transform_thread);
 
                OCIO_processorRelease(processor);
        }
@@ -1012,12 +1029,13 @@ void IMB_colormanagement_imbuf_to_role(ImBuf *ibuf, int role)
        if (ibuf->rect_float) {
                const char *from_colorspace = global_role_scene_linear;
                const char *to_colorspace = role_colorspace_name_get(role);
+               int predivide = ibuf->flags & IB_cm_predivide;
 
                if (ibuf->rect)
                        imb_freerectImBuf(ibuf);
 
                IMB_colormanagement_colorspace_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
-                                                        from_colorspace, to_colorspace);
+                                                        from_colorspace, to_colorspace, predivide);
        }
 #else
        (void) ibuf;
@@ -1031,12 +1049,13 @@ void IMB_colormanagement_imbuf_from_role(ImBuf *ibuf, int role)
        if (ibuf->rect_float) {
                const char *from_colorspace = role_colorspace_name_get(role);
                const char *to_colorspace = global_role_scene_linear;
+               int predivide = ibuf->flags & IB_cm_predivide;
 
                if (ibuf->rect)
                        imb_freerectImBuf(ibuf);
 
                IMB_colormanagement_colorspace_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
-                                                        from_colorspace, to_colorspace);
+                                                        from_colorspace, to_colorspace, predivide);
        }
 #else
        (void) ibuf;
@@ -1090,9 +1109,10 @@ void IMB_colormanagement_imbuf_make_scene_linear(ImBuf *ibuf, ColorManagedColors
        if (ibuf->rect_float) {
                const char *from_colorspace = colorspace_settings->name;
                const char *to_colorspace = global_role_scene_linear;
+               int predivide = ibuf->flags & IB_cm_predivide;
 
                IMB_colormanagement_colorspace_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
-                                                        from_colorspace, to_colorspace);
+                                                        from_colorspace, to_colorspace, predivide);
        }
 #else
        (void) ibuf;
@@ -1879,7 +1899,10 @@ static void partial_buffer_update_rect(unsigned char *display_buffer, const floa
 
                                copy_v4_v4(pixel, (float *) linear_buffer + linear_index);
 
-                               OCIO_processorApplyRGBA(processor, pixel);
+                               if (predivide)
+                                       OCIO_processorApplyRGBA_predivide(processor, pixel);
+                               else
+                                       OCIO_processorApplyRGBA(processor, pixel);
 
                                rgba_float_to_uchar(display_buffer + display_index, pixel);
                        }