Color management fixes

Now it's a bit more robust, tagging images with profiles when they're loaded, 
which then get interpreted later on by conversion functions. Just Linear RGB 
and sRGB profiles at the moment, same as before.

This commit fixes Martin's problem with EXRs and Multilayer images loading/
saving too dark, and it also makes the sequence editor work correctly with it too.

Also fixes:
[#19647] gamma correction with color management is reset when resetting Curve
[#19454] 2.5: Dither does not work when Color management is enabled
This commit is contained in:
2010-01-09 00:16:35 +00:00
parent e62e66fe8a
commit 04dec46c6a
23 changed files with 166 additions and 82 deletions

View File

@@ -143,6 +143,9 @@ struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct Im
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
/* frees all ibufs used by any image datablocks */
void BKE_image_free_image_ibufs(void);
/* goes over all textures that use images */
void BKE_image_free_all_textures(void);

View File

@@ -763,10 +763,16 @@ void colorcorrection_do_ibuf(ImBuf *ibuf, const char *profile)
}
}
/* only used for image editor curves */
void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf)
{
ImBuf *tmpbuf;
int pixel;
char *tmpcbuf;
float *pix_in;
float col[3];
int stride= 4;
float *pix_out;
if(ibuf==NULL)
return;
@@ -775,35 +781,45 @@ void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf)
else if(ibuf->rect==NULL)
imb_addrectImBuf(ibuf);
if (!ibuf->rect || !ibuf->rect_float)
return;
/* work on a temp buffer, so can color manage afterwards.
* No worse off memory wise than comp nodes */
tmpbuf = IMB_dupImBuf(ibuf);
curvemapping_premultiply(cumap, 0);
if(ibuf->rect_float && ibuf->rect) {
float *pixf= ibuf->rect_float;
float col[3];
int stride= 4;
char *pixc= (char *)ibuf->rect;
if(ibuf->channels)
stride= ibuf->channels;
for(pixel= ibuf->x*ibuf->y; pixel>0; pixel--, pixf+=stride, pixc+=4) {
if(stride<3) {
col[0]= curvemap_evaluateF(cumap->cm, *pixf);
pixc[1]= pixc[2]= pixc[3]= pixc[0]= FTOCHAR(col[0]);
}
else {
curvemapping_evaluate_premulRGBF(cumap, col, pixf);
pixc[0]= FTOCHAR(col[0]);
pixc[1]= FTOCHAR(col[1]);
pixc[2]= FTOCHAR(col[2]);
if(stride>3)
pixc[3]= FTOCHAR(pixf[3]);
else
pixc[3]= 255;
}
pix_in= ibuf->rect_float;
pix_out= tmpbuf->rect_float;
// pixc= (char *)ibuf->rect;
if(ibuf->channels)
stride= ibuf->channels;
for(pixel= ibuf->x*ibuf->y; pixel>0; pixel--, pix_in+=stride, pix_out+=4) {
if(stride<3) {
col[0]= curvemap_evaluateF(cumap->cm, *pix_in);
pix_out[1]= pix_out[2]= pix_out[3]= pix_out[0]= col[0];
}
else {
curvemapping_evaluate_premulRGBF(cumap, col, pix_in);
pix_out[0]= col[0];
pix_out[1]= col[1];
pix_out[2]= col[2];
if(stride>3)
pix_out[3]= pix_in[3];
else
pix_out[3]= 1.f;
}
}
IMB_rect_from_float(tmpbuf);
SWAP(char *, tmpbuf->rect, ibuf->rect);
IMB_freeImBuf(tmpbuf);
curvemapping_premultiply(cumap, 1);
}

View File

@@ -725,6 +725,17 @@ void BKE_image_print_memlist(void)
}
}
/* frees all ibufs used by any image datablocks */
void BKE_image_free_image_ibufs(void)
{
Image *ima;
for(ima= G.main->image.first; ima; ima= ima->id.next) {
image_free_buffers(ima);
}
}
void BKE_image_free_all_textures(void)
{
Tex *tex;
@@ -1898,6 +1909,7 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
ibuf->rect_float= rpass->rect;
ibuf->flags |= IB_rectfloat;
ibuf->channels= rpass->channels;
ibuf->profile = IB_PROFILE_LINEAR_RGB;
image_assign_ibuf(ima, ibuf, iuser?iuser->multi_index:IMA_NO_INDEX, 0);
}

View File

@@ -1694,7 +1694,19 @@ static void input_preprocess(Scene *scene, Sequence *seq, TStripElem *se, int cf
if(seq->flag & SEQ_MAKE_FLOAT) {
if (!se->ibuf->rect_float) {
IMB_float_from_rect(se->ibuf);
if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
IMB_float_from_rect(se->ibuf);
} else {
int profile = IB_PROFILE_NONE;
/* no color management:
* don't disturb the existing profiles */
SWAP(int, se->ibuf->profile, profile);
IMB_float_from_rect(se->ibuf);
SWAP(int, se->ibuf->profile, profile);
}
}
if (se->ibuf->rect) {
imb_freerectImBuf(se->ibuf);

View File

@@ -4081,10 +4081,17 @@ static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
s->clonecanvas= ibuf;
/* temporarily add float rect for cloning */
if(s->canvas->rect_float && !s->clonecanvas->rect_float) {
/* temporarily add float rect for cloning */
int profile = IB_PROFILE_NONE;
/* Don't want to color manage, but don't disturb existing profiles */
SWAP(int, s->clonecanvas->profile, profile);
IMB_float_from_rect(s->clonecanvas);
s->clonefreefloat= 1;
SWAP(int, s->clonecanvas->profile, profile);
}
else if(!s->canvas->rect_float && !s->clonecanvas->rect)
IMB_rect_from_float(s->clonecanvas);

View File

@@ -126,7 +126,7 @@ static void image_verify_buffer_float(SpaceImage *sima, Image *ima, ImBuf *ibuf,
else {
if (color_manage) {
if (ima && ima->source == IMA_SRC_VIEWER)
ibuf->profile = IB_PROFILE_SRGB;
ibuf->profile = IB_PROFILE_LINEAR_RGB;
} else {
ibuf->profile = IB_PROFILE_NONE;
}

View File

@@ -1269,7 +1269,7 @@ void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
if(!ibuf->rect) {
if(color_manage)
ibuf->profile= IB_PROFILE_SRGB;
ibuf->profile = IB_PROFILE_LINEAR_RGB;
else
ibuf->profile = IB_PROFILE_NONE;
IMB_rect_from_float(ibuf);

View File

@@ -699,8 +699,14 @@ void draw_image_seq(Scene *scene, ARegion *ar, SpaceSeq *sseq)
break;
}
if(ibuf->rect_float && ibuf->rect==NULL)
IMB_rect_from_float(ibuf);
if(ibuf->rect_float && ibuf->rect==NULL) {
if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
ibuf->profile = IB_PROFILE_LINEAR_RGB;
} else {
ibuf->profile = IB_PROFILE_NONE;
}
IMB_rect_from_float(ibuf);
}
/* needed for gla draw */
glaDefine2DArea(&ar->winrct);

View File

@@ -452,6 +452,7 @@ struct ImBuf *imb_loadamiga(int *iffmem,int flags)
if (ibuf == 0) return (0);
ibuf->ftype = (ftype | AMI);
ibuf->profile = IB_PROFILE_SRGB;
if (cmap){
ibuf->mincol = 0;

View File

@@ -175,6 +175,7 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, int size, int flags)
if (ibuf) {
ibuf->ftype = BMP;
ibuf->profile = IB_PROFILE_SRGB;
}
return(ibuf);

View File

@@ -101,6 +101,7 @@ struct ImBuf *imb_load_dds(unsigned char *mem, int size, int flags)
if (ibuf == 0) return(0); /* memory allocation failed */
ibuf->ftype = DDS;
ibuf->profile = IB_PROFILE_SRGB;
if ((flags & IB_test) == 0) {
if (!imb_addrectImBuf(ibuf)) return(ibuf);

View File

@@ -175,12 +175,14 @@ void IMB_gamwarp(struct ImBuf *ibuf, double gamma)
}
/* assume converting from linear float to sRGB byte */
void IMB_rect_from_float(struct ImBuf *ibuf)
{
/* quick method to convert floatbuf to byte */
float *tof = (float *)ibuf->rect_float;
float dither= ibuf->dither;
float srgb[3];
int do_dither = ibuf->dither != 0.f;
float dither= ibuf->dither / 255.0;
float srgb[4];
int i, channels= ibuf->channels;
short profile= ibuf->profile;
unsigned char *to = (unsigned char *) ibuf->rect;
@@ -195,7 +197,7 @@ void IMB_rect_from_float(struct ImBuf *ibuf)
for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof++)
to[1]= to[2]= to[3]= to[0] = FTOCHAR(tof[0]);
}
else if (profile == IB_PROFILE_SRGB) {
else if (profile == IB_PROFILE_LINEAR_RGB) {
if(channels == 3) {
for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) {
srgb[0]= linearrgb_to_srgb(tof[0]);
@@ -209,10 +211,26 @@ void IMB_rect_from_float(struct ImBuf *ibuf)
}
}
else if (channels == 4) {
floatbuf_to_srgb_byte(tof, to, 0, ibuf->x, 0, ibuf->y, ibuf->x);
if (dither != 0.f) {
for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
const float d = (BLI_frand()-0.5)*dither;
srgb[0]= d + linearrgb_to_srgb(tof[0]);
srgb[1]= d + linearrgb_to_srgb(tof[1]);
srgb[2]= d + linearrgb_to_srgb(tof[2]);
srgb[3]= d + tof[3];
to[0] = FTOCHAR(srgb[0]);
to[1] = FTOCHAR(srgb[1]);
to[2] = FTOCHAR(srgb[2]);
to[3] = FTOCHAR(srgb[3]);
}
} else {
floatbuf_to_srgb_byte(tof, to, 0, ibuf->x, 0, ibuf->y, ibuf->x);
}
}
}
else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_LINEAR_RGB) && dither==0.0f) {
else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) {
if(channels==3) {
for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) {
to[0] = FTOCHAR(tof[0]);
@@ -222,32 +240,26 @@ void IMB_rect_from_float(struct ImBuf *ibuf)
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
to[0] = FTOCHAR(tof[0]);
to[1] = FTOCHAR(tof[1]);
to[2] = FTOCHAR(tof[2]);
to[3] = FTOCHAR(tof[3]);
if (dither != 0.f) {
float col[3];
for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
const float d = (BLI_frand()-0.5)*dither;
const float col[4] = {d+tof[0], d+tof[1], d+tof[2], d+tof[3]};
to[0] = FTOCHAR(col[0]);
to[1] = FTOCHAR(col[1]);
to[2] = FTOCHAR(col[2]);
to[3] = FTOCHAR(col[3]);
}
} else {
for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
to[0] = FTOCHAR(tof[0]);
to[1] = FTOCHAR(tof[1]);
to[2] = FTOCHAR(tof[2]);
to[3] = FTOCHAR(tof[3]);
}
}
}
}
else {
float dither_value, col;
dither= dither/255.0f;
for (i = ibuf->x * ibuf->y; i > 0; i--) {
dither_value = (BLI_frand()-0.5)*dither;
col= tof[0] + dither_value;
to[0] = FTOCHAR(col);
col= tof[1] + dither_value;
to[1] = FTOCHAR(col);
col= tof[2] + dither_value;
to[2] = FTOCHAR(col);
col= tof[3] + dither_value;
to[3] = FTOCHAR(col);
to += 4;
tof += 4;
}
}
}
void IMB_float_from_rect(struct ImBuf *ibuf)
@@ -263,8 +275,11 @@ void IMB_float_from_rect(struct ImBuf *ibuf)
tof = ibuf->rect_float;
}
if (ibuf->profile == IB_PROFILE_SRGB) {
/* convert from srgb to linear rgb */
/* Float bufs should be stored linear */
if (ibuf->profile != IB_PROFILE_NONE) {
/* if the image has been given a profile then we're working
* with color management in mind, so convert it to linear space */
for (i = ibuf->x * ibuf->y; i > 0; i--)
{

View File

@@ -387,6 +387,7 @@ struct ImBuf *imb_loadanim(int *iffmem, int flags)
if (ibuf==0) return (0);
ibuf->ftype = (Anim | adat.type);
ibuf->profile = IB_PROFILE_SRGB;
ibuf->xorig = adat.xorig;
ibuf->yorig = adat.yorig;
ibuf->flags = flags;

View File

@@ -494,6 +494,7 @@ struct ImBuf *imb_loadiris(unsigned char *mem, int flags)
}
ibuf->ftype = IMAGIC;
ibuf->profile = IB_PROFILE_SRGB;
if (flags & IB_ttob) IMB_flipy(ibuf);
test_endian_zbuf(ibuf);

View File

@@ -416,6 +416,7 @@ next_stamp_marker:
jpeg_destroy((j_common_ptr) cinfo);
ibuf->ftype = ibuf_ftype;
ibuf->profile = IB_PROFILE_SRGB;
}
return(ibuf);

View File

@@ -933,6 +933,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags)
ibuf = IMB_allocImBuf(width, height, 32, 0, 0);
ibuf->ftype = OPENEXR;
/* openEXR is linear as per EXR spec */
ibuf->profile = IB_PROFILE_LINEAR_RGB;
if (!(flags & IB_test))
{

View File

@@ -368,6 +368,7 @@ struct ImBuf *imb_loadpng(unsigned char *mem, int size, int flags)
if (ibuf) {
ibuf->ftype = PNG;
ibuf->profile = IB_PROFILE_SRGB;
} else {
printf("Couldn't allocate memory for PNG image\n");
}

View File

@@ -204,6 +204,7 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, int size, int flags)
if (ibuf==NULL) return NULL;
ibuf->ftype = RADHDR;
ibuf->profile = IB_PROFILE_LINEAR_RGB;
ibuf->xorig = ibuf->yorig = 0;
if (flags & IB_test) return ibuf;

View File

@@ -161,6 +161,7 @@ ImBuf *IMB_ibImageFromMemory(int *mem, int size, int flags) {
ibuf = imb_cocoaLoadImage((uchar *)mem, size, flags);
if(ibuf) {
ibuf->ftype = TIF;
ibuf->profile = IB_PROFILE_SRGB;
return ibuf;
}
#else

View File

@@ -569,6 +569,7 @@ struct ImBuf *imb_loadtarga(unsigned char *mem, int mem_size, int flags)
if (ibuf == 0) return(0);
ibuf->ftype = TGA;
ibuf->profile = IB_PROFILE_SRGB;
ibuf->xorig = tga.xorig;
ibuf->yorig = tga.yorig;
mem = mem + 18 + tga.numid;

View File

@@ -347,6 +347,7 @@ struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
ibuf = IMB_allocImBuf(width, height, 8*bytesperpixel, 0, 0);
if (ibuf) {
ibuf->ftype = TIF;
ibuf->profile = IB_PROFILE_SRGB;
} else {
fprintf(stderr,
"imb_loadtiff: could not allocate memory for TIFF " \

View File

@@ -96,6 +96,7 @@ EnumPropertyItem snap_element_items[] = {
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_pointcache.h"
@@ -517,6 +518,12 @@ static int rna_SceneRenderData_engine_get(PointerRNA *ptr)
return 0;
}
static void rna_SceneRenderData_color_management_update(Main *bmain, Scene *unused, PointerRNA *ptr)
{
/* reset all generated image block buffers to prevent out-of-date conversions */
BKE_image_free_image_ibufs();
}
static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value)
{
Scene *scene= (Scene*)ptr->id.data;
@@ -2114,7 +2121,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop= RNA_def_property(srna, "color_management", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "color_mgt_flag", R_COLOR_MANAGEMENT);
RNA_def_property_ui_text(prop, "Color Management", "Use color profiles and gamma corrected imaging pipeline");
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_MATERIAL|ND_SHADING, NULL);
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS|NC_MATERIAL|ND_SHADING, "rna_SceneRenderData_color_management_update");
prop= RNA_def_property(srna, "use_file_extension", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_EXTENSION);

View File

@@ -64,27 +64,19 @@ static CompBuf *node_composit_get_image(RenderData *rd, Image *ima, ImageUser *i
ibuf= BKE_image_get_ibuf(ima, iuser);
if(ibuf==NULL)
return NULL;
if (rd->color_mgt_flag & R_COLOR_MANAGEMENT) {
if (ibuf->profile == IB_PROFILE_NONE) {
/* if float buffer already exists = already linear */
/* else ... */
if (ibuf->rect_float == NULL) {
imb_freerectfloatImBuf(ibuf);
ibuf->profile = IB_PROFILE_SRGB;
IMB_float_from_rect(ibuf);
} else {
ibuf->profile = IB_PROFILE_LINEAR_RGB;
}
}
} else {
if (ibuf->profile == IB_PROFILE_SRGB) {
if (ibuf->rect_float != NULL) {
imb_freerectfloatImBuf(ibuf);
}
ibuf->profile = IB_PROFILE_NONE;
IMB_float_from_rect(ibuf);
if (!(rd->color_mgt_flag & R_COLOR_MANAGEMENT)) {
int profile = IB_PROFILE_NONE;
/* temporarily set profile to none to not disturb actual */
SWAP(int, ibuf->profile, profile);
if (ibuf->rect_float != NULL) {
imb_freerectfloatImBuf(ibuf);
}
IMB_float_from_rect(ibuf);
SWAP(int, ibuf->profile, profile);
}
if (ibuf->rect_float == NULL) {