Color Management: add View as Render to image datablocks

This is need since some images (like normal maps, textures and so) would
want to be viewed without any tone map applied on them. On the same time
it's possible that some images would want to be affected by tone maps,
and renders would always want to be affected by tone maps.

After long discussion with Brecht we decided less painful and most clear
way would be to simply add "View as Render" option to image datablocks.

If this option is enabled for image, both settings from Display and
Render blocks of color management settings would be applied on display.

If this option is disabled, only display transform with default view and
no exposure/gamma/curves would be applied.

Render result and compositor viewers would always have "View as Render"
enabled.

There's separated setting when image is saving which says whether saved
image should be affected by render part of color management settings.

This option is enabled by default for render result/node viewer and
disabled by default for all the rest images. This option wouldn't have
affect when saving to float formats such as EXR.
This commit is contained in:
Sergey Sharybin
2012-09-10 14:47:47 +00:00
parent b0605eed2c
commit ce3566a4cb
11 changed files with 125 additions and 24 deletions

View File

@@ -246,6 +246,9 @@ static Image *image_alloc(const char *name, short source, short type)
ima->source = source;
ima->type = type;
if (source == IMA_SRC_VIEWER)
ima->flag |= IMA_VIEW_AS_RENDER;
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
}
return ima;

View File

@@ -7926,6 +7926,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* color management pipeline changes compatibility code */
{
Scene *scene;
Image *ima;
for (scene = main->scene.first; scene; scene = scene->id.next) {
if ((scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) == 0) {
@@ -7936,6 +7937,11 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
}
for (ima = main->image.first; ima; ima = ima->id.next) {
if (ima->source == IMA_SRC_VIEWER)
ima->flag |= IMA_VIEW_AS_RENDER;
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */

View File

@@ -80,7 +80,7 @@ int ED_space_image_maskedit_mask_poll(struct bContext *C);
/* UI level image (texture) updating... render calls own stuff (too) */
void ED_image_update_frame(const struct Main *mainp, int cfra);
void ED_image_draw_info(struct Scene *scene, struct ARegion *ar, int color_manage, int channels, int x, int y,
void ED_image_draw_info(struct Scene *scene, struct ARegion *ar, int color_manage, int use_default_view, int channels, int x, int y,
const unsigned char cp[4], const float fp[4], int *zp, float *zpf);
#endif /* __ED_IMAGE_H__ */

View File

@@ -692,6 +692,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
col = uiLayoutColumn(layout, FALSE);
uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings");
uiItemR(col, &imaptr, "view_as_render", 0, NULL, ICON_NONE);
if (ima->source != IMA_SRC_GENERATED) {
if (compact == 0) { /* background image view doesnt need these */

View File

@@ -94,7 +94,7 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar)
}
/* used by node view too */
void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int channels, int x, int y,
void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_default_view, int channels, int x, int y,
const unsigned char cp[4], const float fp[4], int *zp, float *zpf)
{
char str[256];
@@ -195,7 +195,10 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int channel
if (color_manage && channels == 4) {
float pixel[4];
IMB_colormanagement_pixel_to_display_space_v4(pixel, fp, &scene->view_settings, &scene->display_settings);
if (use_default_view)
IMB_colormanagement_pixel_to_display_space_v4(pixel, fp, NULL, &scene->display_settings);
else
IMB_colormanagement_pixel_to_display_space_v4(pixel, fp, &scene->view_settings, &scene->display_settings);
BLI_snprintf(str, sizeof(str), " | CM R:%-.4f G:%-.4f B:%-.4f", pixel[0], pixel[1], pixel[2]);
BLF_position(blf_mono_font, dx, 6, 0);
@@ -245,7 +248,10 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int channel
}
if (color_manage) {
IMB_colormanagement_pixel_to_display_space_v4(finalcol, col, &scene->view_settings, &scene->display_settings);
if (use_default_view)
IMB_colormanagement_pixel_to_display_space_v4(finalcol, col, NULL, &scene->display_settings);
else
IMB_colormanagement_pixel_to_display_space_v4(finalcol, col, &scene->view_settings, &scene->display_settings);
}
else {
copy_v4_v4(finalcol, col);
@@ -491,7 +497,8 @@ static unsigned int *get_part_from_buffer(unsigned int *buffer, int width, short
static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene, Image *ima, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy)
{
unsigned int *display_buffer, *rect;
unsigned char *display_buffer;
unsigned int *rect;
int dx, dy, sx, sy, x, y;
void *cache_handle;
@@ -499,8 +506,10 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene,
if (ima->xrep < 1) return;
if (ima->yrep < 1) return;
display_buffer = (unsigned int *) IMB_display_buffer_acquire(ibuf, &scene->view_settings,
&scene->display_settings, &cache_handle);
if (ima->flag & IMA_VIEW_AS_RENDER)
display_buffer = IMB_display_buffer_acquire(ibuf, &scene->view_settings, &scene->display_settings, &cache_handle);
else
display_buffer = IMB_display_buffer_acquire(ibuf, NULL, &scene->display_settings, &cache_handle);
if (!display_buffer)
return;
@@ -515,7 +524,7 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene,
dy = ibuf->y / ima->yrep;
sx = (sima->curtile % ima->xrep) * dx;
sy = (sima->curtile / ima->xrep) * dy;
rect = get_part_from_buffer(display_buffer, ibuf->x, sx, sy, sx + dx, sy + dy);
rect = get_part_from_buffer((unsigned int*)display_buffer, ibuf->x, sx, sy, sx + dx, sy + dy);
/* draw repeated */
for (sy = 0; sy + dy <= ibuf->y; sy += dy) {

View File

@@ -1183,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;
}
@@ -1195,13 +1197,15 @@ 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, void **cache_handle)
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;
@@ -1211,8 +1215,12 @@ static ImBuf *save_image_colormanaged_imbuf_acquire(ImBuf *ibuf, SaveImageOption
do_colormanagement = !BKE_imtype_supports_float(imf->imtype);
if (do_colormanagement) {
unsigned char *display_buffer =
IMB_display_buffer_acquire(ibuf, &imf->view_settings, &imf->display_settings, cache_handle);
unsigned char *display_buffer;
if (save_as_render)
display_buffer = IMB_display_buffer_acquire(ibuf, &imf->view_settings, &imf->display_settings, cache_handle);
else
display_buffer = IMB_display_buffer_acquire(ibuf, NULL, &imf->display_settings, cache_handle);
if (*cache_handle) {
colormanaged_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, 0);
@@ -1247,6 +1255,7 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
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 */
@@ -1271,7 +1280,7 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
}
colormanaged_ibuf = save_image_colormanaged_imbuf_acquire(ibuf, simopts, &cache_handle);
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);
@@ -1350,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;
}
@@ -1402,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));
@@ -1437,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, TRUE);
uiTemplateImageSettings(layout, &ptr, FALSE);
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
@@ -1465,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,
@@ -1989,6 +2007,7 @@ typedef struct ImageSampleInfo {
int draw;
int color_manage;
int use_default_view;
} ImageSampleInfo;
static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
@@ -1997,7 +2016,8 @@ static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
if (info->draw) {
Scene *scene = CTX_data_scene(C);
ED_image_draw_info(scene, ar, info->color_manage, info->channels, info->x, info->y, info->colp, info->colfp, info->zp, info->zfp);
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);
}
}
@@ -2070,6 +2090,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);
@@ -2083,7 +2104,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);

View File

@@ -341,7 +341,7 @@ static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
ImageSampleInfo *info = arg_info;
if (info->draw) {
ED_image_draw_info(scene, ar, info->color_manage, info->channels,
ED_image_draw_info(scene, ar, info->color_manage, FALSE, info->channels,
info->x, info->y, info->col, info->colf,
NULL, NULL /* zbuf - unused for nodes */
);

View File

@@ -80,7 +80,7 @@ static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
ImageSampleInfo *info = arg_info;
if (info->draw) {
ED_image_draw_info(scene, ar, info->color_manage, info->channels,
ED_image_draw_info(scene, ar, info->color_manage, FALSE, info->channels,
info->x, info->y, info->colp, info->colfp, NULL, NULL);
}
}

View File

@@ -635,9 +635,15 @@ static void display_transform_get_from_ctx(const bContext *C, ColorManagedViewSe
ColorManagedDisplaySettings **display_settings_r)
{
Scene *scene = CTX_data_scene(C);
SpaceImage *sima = CTX_wm_space_image(C);
*view_settings_r = &scene->view_settings;
*display_settings_r = &scene->display_settings;
if (sima) {
if ((sima->image->flag & IMA_VIEW_AS_RENDER) == 0)
*view_settings_r = NULL;
}
}
#ifdef WITH_OCIO
@@ -801,6 +807,26 @@ static ConstProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDispla
return (ConstProcessorRcPtr *) display->to_scene_linear;
}
static void init_default_view_settings(const ColorManagedDisplaySettings *display_settings,
ColorManagedViewSettings *view_settings)
{
ColorManagedDisplay *display;
ColorManagedView *default_view;
display = colormanage_display_get_named(display_settings->display_device);
default_view = colormanage_view_get_default(display);
if (default_view)
BLI_strncpy(view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
else
view_settings->view_transform[0] = '\0';
view_settings->flag = 0;
view_settings->gamma = 1.0f;
view_settings->exposure = 0.0f;
view_settings->curve_mapping = NULL;
}
#endif
static void curve_mapping_apply_pixel(CurveMapping *curve_mapping, float *pixel, int channels)
@@ -1763,8 +1789,22 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
int buffer_size;
ColormanageCacheViewSettings cache_view_settings;
ColormanageCacheDisplaySettings cache_display_settings;
ColorManagedViewSettings default_view_settings;
const ColorManagedViewSettings *applied_view_settings;
colormanage_view_settings_to_cache(&cache_view_settings, view_settings);
if (view_settings) {
applied_view_settings = view_settings;
}
else {
/* if no view settings were specified, use default display transformation
* this happens for images which don't want to be displayed with render settings
*/
init_default_view_settings(display_settings, &default_view_settings);
applied_view_settings = &default_view_settings;
}
colormanage_view_settings_to_cache(&cache_view_settings, applied_view_settings);
colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
BLI_lock_thread(LOCK_COLORMANAGE);
@@ -1793,7 +1833,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet
buffer_size = ibuf->channels * ibuf->x * ibuf->y * sizeof(float);
display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
colormanage_display_buffer_process(ibuf, display_buffer, view_settings, display_settings);
colormanage_display_buffer_process(ibuf, display_buffer, applied_view_settings, display_settings);
colormanage_cache_put(ibuf, &cache_view_settings, &cache_display_settings, display_buffer, cache_handle);
@@ -2415,12 +2455,25 @@ ColormanageProcessor *IMB_colormanagement_display_processor_new(const ColorManag
cm_processor = MEM_callocN(sizeof(ColormanageProcessor), "colormanagement processor");
#ifdef WITH_OCIO
cm_processor->processor = create_display_buffer_processor(view_settings->view_transform, display_settings->display_device,
view_settings->exposure, view_settings->gamma);
{
ColorManagedViewSettings default_view_settings;
const ColorManagedViewSettings *applied_view_settings;
if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
cm_processor->curve_mapping = curvemapping_copy(view_settings->curve_mapping);
curvemapping_premultiply(cm_processor->curve_mapping, FALSE);
if (view_settings) {
applied_view_settings = view_settings;
}
else {
init_default_view_settings(display_settings, &default_view_settings);
applied_view_settings = &default_view_settings;
}
cm_processor->processor = create_display_buffer_processor(applied_view_settings->view_transform, display_settings->display_device,
applied_view_settings->exposure, applied_view_settings->gamma);
if (applied_view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
cm_processor->curve_mapping = curvemapping_copy(applied_view_settings->curve_mapping);
curvemapping_premultiply(cm_processor->curve_mapping, FALSE);
}
}
#else
(void) view_settings;

View File

@@ -127,6 +127,7 @@ typedef struct Image {
#define IMA_CM_PREDIVIDE 256
#define IMA_USED_FOR_RENDER 512
#define IMA_USER_FRAME_IN_RANGE 1024 /* for image user, but these flags are mixed */
#define IMA_VIEW_AS_RENDER 2048
/* Image.tpageflag */
#define IMA_TILES 1

View File

@@ -513,6 +513,11 @@ static void rna_def_image(BlenderRNA *brna)
"to avoid fringing for images with light backgrounds");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_free_update");
prop = RNA_def_property(srna, "view_as_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_VIEW_AS_RENDER);
RNA_def_property_ui_text(prop, "View as Render", "Apply render part of display transformation when displaying this image on the screen");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);