Color Management, Stage 2: Switch color pipeline to use OpenColorIO
[blender.git] / source / blender / editors / space_image / image_ops.c
index 52a2bf22d4b7b973b59e752c8878af6623d92c81..16804c5a1c66b1c5ed2bfc85136f1afe8f1377ba 100644 (file)
@@ -55,6 +55,7 @@
 #include "BKE_report.h"
 #include "BKE_screen.h"
 
+#include "IMB_colormanagement.h"
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
 
@@ -1168,6 +1169,10 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
                        }
                        BLI_path_abs(simopts->filepath, G.main->name);
                }
+
+               /* color management */
+               BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
+               BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
        }
 
        ED_space_image_release_buffer(sima, lock);
@@ -1178,6 +1183,8 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
 static void save_image_options_from_op(SaveImageOptions *simopts, wmOperator *op)
 {
        if (op->customdata) {
+               BKE_color_managed_view_settings_free(&simopts->im_format.view_settings);
+
                simopts->im_format = *(ImageFormatData *)op->customdata;
        }
 
@@ -1190,12 +1197,47 @@ static void save_image_options_from_op(SaveImageOptions *simopts, wmOperator *op
 static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op)
 {
        if (op->customdata) {
+               BKE_color_managed_view_settings_free(&((ImageFormatData *)op->customdata)->view_settings);
+
                *(ImageFormatData *)op->customdata = simopts->im_format;
        }
 
        RNA_string_set(op->ptr, "filepath", simopts->filepath);
 }
 
+static ImBuf *save_image_colormanaged_imbuf_acquire(ImBuf *ibuf, SaveImageOptions *simopts, int save_as_render, void **cache_handle)
+{
+       ImageFormatData *imf = &simopts->im_format;
+       ImBuf *colormanaged_ibuf;
+       int do_colormanagement;
+
+       *cache_handle = NULL;
+       do_colormanagement = save_as_render && !BKE_imtype_supports_float(imf->imtype);
+
+       if (do_colormanagement) {
+               unsigned char *display_buffer;
+
+               display_buffer = IMB_display_buffer_acquire(ibuf, &imf->view_settings, &imf->display_settings, cache_handle);
+
+               if (*cache_handle) {
+                       colormanaged_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, 0);
+                       colormanaged_ibuf->rect = (unsigned int *) display_buffer;
+               }
+               else {
+                       /* no cache handle means color management didn't run transformation
+                        * or performed transformation to image's byte buffer which doesn't
+                        * require allocating new image buffer
+                        */
+                       colormanaged_ibuf = ibuf;
+               }
+       }
+       else {
+               colormanaged_ibuf = ibuf;
+       }
+
+       return colormanaged_ibuf;
+}
+
 /* assumes name is FILE_MAX */
 /* ima->name and ibuf->name should end up the same */
 static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, int do_newpath)
@@ -1205,9 +1247,12 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
        ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
 
        if (ibuf) {
+               void *cache_handle;
+               ImBuf *colormanaged_ibuf;
                const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id);
                const short relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path"));
                const short save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
+               const short save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render"));
                short ok = FALSE;
 
                /* old global to ensure a 2nd save goes to same dir */
@@ -1231,7 +1276,9 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
                                ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? 32 : 24;
                        }
                }
-               
+
+               colormanaged_ibuf = save_image_colormanaged_imbuf_acquire(ibuf, simopts, save_as_render, &cache_handle);
+
                if (simopts->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
                        Scene *scene = CTX_data_scene(C);
                        RenderResult *rr = BKE_image_acquire_renderresult(scene, ima);
@@ -1245,7 +1292,8 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
                        BKE_image_release_renderresult(scene, ima);
                }
                else {
-                       if (BKE_imbuf_write_as(ibuf, simopts->filepath, &simopts->im_format, save_copy)) {
+                       if (BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, &simopts->im_format, save_copy))
+                       {
                                ok = TRUE;
                        }
                }
@@ -1284,6 +1332,8 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
                                if (relative) {
                                        BLI_path_rel(ima->name, relbase); /* only after saving */
                                }
+
+                               IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
                        }
                }
                else {
@@ -1294,6 +1344,13 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
                WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
 
                WM_cursor_wait(0);
+
+               if (cache_handle) {
+                       colormanaged_ibuf->rect = NULL;
+                       IMB_freeImBuf(colormanaged_ibuf);
+
+                       IMB_display_buffer_release(cache_handle);
+               }
        }
 
        ED_space_image_release_buffer(sima, lock);
@@ -1302,6 +1359,9 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
 static void image_save_as_free(wmOperator *op)
 {
        if (op->customdata) {
+               ImageFormatData *im_format = (ImageFormatData *)op->customdata;
+               BKE_color_managed_view_settings_free(&im_format->view_settings);
+
                MEM_freeN(op->customdata);
                op->customdata = NULL;
        }
@@ -1354,6 +1414,11 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(eve
                RNA_boolean_set(op->ptr, "copy", TRUE);
        }
 
+       if (ima->source == IMA_SRC_VIEWER)
+               RNA_boolean_set(op->ptr, "save_as_render", TRUE);
+       else
+               RNA_boolean_set(op->ptr, "save_as_render", FALSE);
+
        op->customdata = MEM_mallocN(sizeof(simopts.im_format), __func__);
        memcpy(op->customdata, &simopts.im_format, sizeof(simopts.im_format));
 
@@ -1389,7 +1454,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
 
        /* image template */
        RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &ptr);
-       uiTemplateImageSettings(layout, &ptr);
+       uiTemplateImageSettings(layout, &ptr, FALSE);
 
        /* main draw call */
        RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
@@ -1417,6 +1482,7 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
        /* properties */
+       RNA_def_boolean(ot->srna, "save_as_render", 0, "Save As Render", "Apply render part of display transform when saving byte image");
        RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender");
 
        WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_SAVE,
@@ -1601,8 +1667,10 @@ static int image_new_exec(bContext *C, wmOperator *op)
        RNA_float_get_array(op->ptr, "color", color);
        alpha = RNA_boolean_get(op->ptr, "alpha");
        
-       if (!floatbuf && scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
+       if (!floatbuf) {
+               /* OCIO_TODO: perhaps we need to convert to display space, not just to sRGB */
                linearrgb_to_srgb_v3_v3(color, color);
+       }
 
        if (!alpha)
                color[3] = 1.0f;
@@ -1938,14 +2006,18 @@ typedef struct ImageSampleInfo {
        float *zfp;
 
        int draw;
+       int color_manage;
+       int use_default_view;
 } ImageSampleInfo;
 
-static void image_sample_draw(const bContext *UNUSED(C), ARegion *ar, void *arg_info)
+static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
 {
        ImageSampleInfo *info = arg_info;
        if (info->draw) {
-               /* no color management needed for images (color_manage=0) */
-               ED_image_draw_info(ar, 0, info->channels, info->x, info->y, info->colp, info->colfp, info->zp, info->zfp);
+               Scene *scene = CTX_data_scene(C);
+
+               ED_image_draw_info(scene, ar, info->color_manage, info->use_default_view, info->channels,
+                                  info->x, info->y, info->colp, info->colfp, info->zp, info->zfp);
        }
 }
 
@@ -1975,13 +2047,7 @@ int ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], floa
 
                if (ibuf->rect_float) {
                        fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
-
-                       if (ELEM(ibuf->profile, IB_PROFILE_LINEAR_RGB, IB_PROFILE_NONE)) {
-                               linearrgb_to_srgb_v3_v3(r_col, fp);
-                       }
-                       else {
-                               copy_v3_v3(r_col, fp);
-                       }
+                       linearrgb_to_srgb_v3_v3(r_col, fp);
                        ret = TRUE;
                }
                else if (ibuf->rect) {
@@ -2003,7 +2069,9 @@ static void image_sample_apply(bContext *C, wmOperator *op, wmEvent *event)
        ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
        ImageSampleInfo *info = op->customdata;
        float fx, fy;
-       
+       Scene *scene = CTX_data_scene(C);
+       CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
+
        if (ibuf == NULL) {
                ED_space_image_release_buffer(sima, lock);
                info->draw = 0;
@@ -2016,6 +2084,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, wmEvent *event)
                float *fp;
                unsigned char *cp;
                int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
+               Image *image = ED_space_image(sima);
 
                CLAMP(x, 0, ibuf->x - 1);
                CLAMP(y, 0, ibuf->y - 1);
@@ -2029,7 +2098,9 @@ static void image_sample_apply(bContext *C, wmOperator *op, wmEvent *event)
                info->colfp = NULL;
                info->zp = NULL;
                info->zfp = NULL;
-               
+
+               info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? FALSE : TRUE;
+
                if (ibuf->rect) {
                        cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
 
@@ -2044,6 +2115,8 @@ static void image_sample_apply(bContext *C, wmOperator *op, wmEvent *event)
                        info->colf[2] = (float)cp[2] / 255.0f;
                        info->colf[3] = (float)cp[3] / 255.0f;
                        info->colfp = info->colf;
+
+                       info->color_manage = FALSE;
                }
                if (ibuf->rect_float) {
                        fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
@@ -2053,6 +2126,8 @@ static void image_sample_apply(bContext *C, wmOperator *op, wmEvent *event)
                        info->colf[2] = fp[2];
                        info->colf[3] = fp[3];
                        info->colfp = info->colf;
+
+                       info->color_manage = TRUE;
                }
 
                if (ibuf->zbuf) {
@@ -2063,25 +2138,21 @@ static void image_sample_apply(bContext *C, wmOperator *op, wmEvent *event)
                        info->zf = ibuf->zbuf_float[y * ibuf->x + x];
                        info->zfp = &info->zf;
                }
-               
-               if (sima->cumap && ibuf->channels == 4) {
+
+               if (curve_mapping && ibuf->channels == 4) {
                        /* we reuse this callback for set curves point operators */
                        if (RNA_struct_find_property(op->ptr, "point")) {
                                int point = RNA_enum_get(op->ptr, "point");
 
                                if (point == 1) {
-                                       curvemapping_set_black_white(sima->cumap, NULL, info->colfp);
-                                       if (ibuf->rect_float)
-                                               curvemapping_do_ibuf(sima->cumap, ibuf);
+                                       curvemapping_set_black_white(curve_mapping, NULL, info->colfp);
                                }
                                else if (point == 0) {
-                                       curvemapping_set_black_white(sima->cumap, info->colfp, NULL);
-                                       if (ibuf->rect_float)
-                                               curvemapping_do_ibuf(sima->cumap, ibuf);
+                                       curvemapping_set_black_white(curve_mapping, info->colfp, NULL);
                                }
                        }
                }
-                               
+
                // XXX node curve integration ..
 #if 0
                {
@@ -2211,7 +2282,7 @@ static int image_sample_line_exec(bContext *C, wmOperator *op)
        hist->co[1][0] = x2f;
        hist->co[1][1] = y2f;
 
-       BKE_histogram_update_sample_line(hist, ibuf, (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) != 0);
+       BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings);
        
        /* reset y zoom */
        hist->ymax = 1.0f;
@@ -2306,7 +2377,8 @@ static int image_record_composite_apply(bContext *C, wmOperator *op)
        
        BKE_image_all_free_anim_ibufs(scene->r.cfra);
        ntreeCompositTagAnimated(scene->nodetree);
-       ntreeCompositExecTree(scene->nodetree, &scene->r, 0, scene->r.cfra != rcd->old_cfra);  /* 1 is no previews */
+       ntreeCompositExecTree(scene->nodetree, &scene->r, 0, scene->r.cfra != rcd->old_cfra,
+                             &scene->view_settings, &scene->display_settings);  /* 1 is no previews */
 
        ED_area_tag_redraw(CTX_wm_area(C));