Fix #32603: Multi-Layer EXR files can't be color managed
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.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user