Blender  V2.59
divers.c
Go to the documentation of this file.
00001 /*
00002  *
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): none yet.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  * allocimbuf.c
00028  *
00029  * $Id: divers.c 37783 2011-06-24 03:49:56Z campbellbarton $
00030  */
00031 
00037 #include "BLI_blenlib.h"
00038 #include "BLI_rand.h"
00039 #include "BLI_math.h"
00040 #include "BLI_utildefines.h"
00041 
00042 #include "imbuf.h"
00043 #include "IMB_imbuf_types.h"
00044 #include "IMB_imbuf.h"
00045 #include "IMB_allocimbuf.h"
00046 
00047 #include "BKE_colortools.h"
00048 
00049 #include "MEM_guardedalloc.h"
00050 
00051 void IMB_de_interlace(struct ImBuf *ibuf)
00052 {
00053         struct ImBuf * tbuf1, * tbuf2;
00054         
00055         if (ibuf == NULL) return;
00056         if (ibuf->flags & IB_fields) return;
00057         ibuf->flags |= IB_fields;
00058         
00059         if (ibuf->rect) {
00060                 /* make copies */
00061                 tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
00062                 tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
00063                 
00064                 ibuf->x *= 2;   
00065                 IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
00066                 IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
00067         
00068                 ibuf->x /= 2;
00069                 IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
00070                 IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y);
00071                 
00072                 IMB_freeImBuf(tbuf1);
00073                 IMB_freeImBuf(tbuf2);
00074         }
00075         ibuf->y /= 2;
00076 }
00077 
00078 void IMB_interlace(struct ImBuf *ibuf)
00079 {
00080         struct ImBuf * tbuf1, * tbuf2;
00081 
00082         if (ibuf == NULL) return;
00083         ibuf->flags &= ~IB_fields;
00084 
00085         ibuf->y *= 2;
00086 
00087         if (ibuf->rect) {
00088                 /* make copies */
00089                 tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
00090                 tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
00091 
00092                 IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
00093                 IMB_rectcpy(tbuf2, ibuf, 0, 0, 0, tbuf2->y, ibuf->x, ibuf->y);
00094 
00095                 ibuf->x *= 2;
00096                 IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
00097                 IMB_rectcpy(ibuf, tbuf2, tbuf2->x, 0, 0, 0, tbuf2->x, tbuf2->y);
00098                 ibuf->x /= 2;
00099 
00100                 IMB_freeImBuf(tbuf1);
00101                 IMB_freeImBuf(tbuf2);
00102         }
00103 }
00104 
00105 
00106 /* assume converting from linear float to sRGB byte */
00107 void IMB_rect_from_float(struct ImBuf *ibuf)
00108 {
00109         /* quick method to convert floatbuf to byte */
00110         float *tof = (float *)ibuf->rect_float;
00111 //      int do_dither = ibuf->dither != 0.f;
00112         float dither= ibuf->dither / 255.0f;
00113         float srgb[4];
00114         int i, channels= ibuf->channels;
00115         short profile= ibuf->profile;
00116         unsigned char *to = (unsigned char *) ibuf->rect;
00117         
00118         if(tof==NULL) return;
00119         if(to==NULL) {
00120                 imb_addrectImBuf(ibuf);
00121                 to = (unsigned char *) ibuf->rect;
00122         }
00123         
00124         if(channels==1) {
00125                 for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof++)
00126                         to[1]= to[2]= to[3]= to[0] = FTOCHAR(tof[0]);
00127         }
00128         else if (profile == IB_PROFILE_LINEAR_RGB) {
00129                 if(channels == 3) {
00130                         for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) {
00131                                 srgb[0]= linearrgb_to_srgb(tof[0]);
00132                                 srgb[1]= linearrgb_to_srgb(tof[1]);
00133                                 srgb[2]= linearrgb_to_srgb(tof[2]);
00134 
00135                                 to[0] = FTOCHAR(srgb[0]);
00136                                 to[1] = FTOCHAR(srgb[1]);
00137                                 to[2] = FTOCHAR(srgb[2]);
00138                                 to[3] = 255;
00139                         }
00140                 }
00141                 else if (channels == 4) {
00142                         if (dither != 0.f) {
00143                                 for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
00144                                         const float d = (BLI_frand()-0.5f)*dither;
00145                                         
00146                                         srgb[0]= d + linearrgb_to_srgb(tof[0]);
00147                                         srgb[1]= d + linearrgb_to_srgb(tof[1]);
00148                                         srgb[2]= d + linearrgb_to_srgb(tof[2]);
00149                                         srgb[3]= d + tof[3]; 
00150                                         
00151                                         to[0] = FTOCHAR(srgb[0]);
00152                                         to[1] = FTOCHAR(srgb[1]);
00153                                         to[2] = FTOCHAR(srgb[2]);
00154                                         to[3] = FTOCHAR(srgb[3]);
00155                                 }
00156                         } else {
00157                                 floatbuf_to_srgb_byte(tof, to, 0, ibuf->x, 0, ibuf->y, ibuf->x);
00158                         }
00159                 }
00160         }
00161         else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) {
00162                 if(channels==3) {
00163                         for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) {
00164                                 to[0] = FTOCHAR(tof[0]);
00165                                 to[1] = FTOCHAR(tof[1]);
00166                                 to[2] = FTOCHAR(tof[2]);
00167                                 to[3] = 255;
00168                         }
00169                 }
00170                 else {
00171                         if (dither != 0.f) {
00172                                 for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
00173                                         const float d = (BLI_frand()-0.5f)*dither;
00174                                         float col[4];
00175 
00176                                         col[0]= d + tof[0];
00177                                         col[1]= d + tof[1];
00178                                         col[2]= d + tof[2];
00179                                         col[3]= d + tof[3];
00180 
00181                                         to[0] = FTOCHAR(col[0]);
00182                                         to[1] = FTOCHAR(col[1]);
00183                                         to[2] = FTOCHAR(col[2]);
00184                                         to[3] = FTOCHAR(col[3]);
00185                                 }
00186                         } else {
00187                                 for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
00188                                         to[0] = FTOCHAR(tof[0]);
00189                                         to[1] = FTOCHAR(tof[1]);
00190                                         to[2] = FTOCHAR(tof[2]);
00191                                         to[3] = FTOCHAR(tof[3]);
00192                                 }
00193                         }
00194                 }
00195         }
00196         /* ensure user flag is reset */
00197         ibuf->userflags &= ~IB_RECT_INVALID;
00198 }
00199 
00200  
00201 
00202 /* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */
00203 void IMB_partial_rect_from_float(struct ImBuf *ibuf,float *buffer, int x, int y, int w, int h)
00204 {
00205         /* indices to source and destination image pixels */
00206         float *srcFloatPxl;
00207         unsigned char *dstBytePxl;
00208         /* buffer index will fill buffer */
00209         float *bufferIndex;
00210 
00211         /* convenience pointers to start of image buffers */
00212         float *init_srcFloatPxl = (float *)ibuf->rect_float;
00213         unsigned char *init_dstBytePxl = (unsigned char *) ibuf->rect;
00214 
00215         /* Dithering factor */
00216         float dither= ibuf->dither / 255.0f;
00217         /* respective attributes of image */
00218         short profile= ibuf->profile;
00219         int channels= ibuf->channels;
00220         
00221         int i, j;
00222         
00223         /*
00224                 if called -only- from GPU_paint_update_image this test will never fail
00225                 but leaving it here for better or worse
00226         */
00227         if(init_srcFloatPxl==NULL || (buffer == NULL)){
00228                 return;
00229         }
00230         if(init_dstBytePxl==NULL) {
00231                 imb_addrectImBuf(ibuf);
00232                 init_dstBytePxl = (unsigned char *) ibuf->rect;
00233         }
00234         if(channels==1) {
00235                         for (j = 0; j < h; j++){
00236                                 bufferIndex = buffer + w*j*4;
00237                                 dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
00238                                 srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x);
00239                                 for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl++, bufferIndex+=4) {
00240                                         dstBytePxl[1]= dstBytePxl[2]= dstBytePxl[3]= dstBytePxl[0] = FTOCHAR(srcFloatPxl[0]);
00241                                         bufferIndex[0] = bufferIndex[1] = bufferIndex[2] = bufferIndex[3] = srcFloatPxl[0];
00242                                 }
00243                         }
00244         }
00245         else if (profile == IB_PROFILE_LINEAR_RGB) {
00246                 if(channels == 3) {
00247                         for (j = 0; j < h; j++){
00248                                 bufferIndex = buffer + w*j*4;
00249                                 dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
00250                                 srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3;
00251                                 for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex += 4) {
00252                                         linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl);
00253                                         F3TOCHAR4(bufferIndex, dstBytePxl);
00254                                         bufferIndex[3]= 1.0;
00255                                 }
00256                         }
00257                 }
00258                 else if (channels == 4) {
00259                         if (dither != 0.f) {
00260                                 for (j = 0; j < h; j++){
00261                                         bufferIndex = buffer + w*j*4;
00262                                         dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
00263                                         srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
00264                                         for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
00265                                                 const float d = (BLI_frand()-0.5f)*dither;
00266                                                 linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl);
00267                                                 bufferIndex[3] = srcFloatPxl[3];
00268                                                 add_v4_fl(bufferIndex, d);
00269                                                 F4TOCHAR4(bufferIndex, dstBytePxl);
00270                                         }
00271                                 }
00272                         } else {
00273                                 for (j = 0; j < h; j++){
00274                                         bufferIndex = buffer + w*j*4;
00275                                         dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
00276                                         srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
00277                                         for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
00278                                                 linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl);
00279                                                 bufferIndex[3]= srcFloatPxl[3];
00280                                                 F4TOCHAR4(bufferIndex, dstBytePxl);
00281                                         }
00282                                 }
00283                         }
00284                 }
00285         }
00286         else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) {
00287                 if(channels==3) {
00288                         for (j = 0; j < h; j++){
00289                                 bufferIndex = buffer + w*j*4;
00290                                 dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
00291                                 srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3;
00292                                 for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex+=4) {
00293                                         copy_v3_v3(bufferIndex, srcFloatPxl);
00294                                         F3TOCHAR4(bufferIndex, dstBytePxl);
00295                                         bufferIndex[3] = 1.0;
00296                                 }
00297                         }
00298                 }
00299                 else {
00300                         if (dither != 0.f) {
00301                                 for (j = 0; j < h; j++){
00302                                         bufferIndex = buffer + w*j*4;
00303                                         dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
00304                                         srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
00305                                         for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
00306                                                 const float d = (BLI_frand()-0.5f)*dither;
00307                                                 copy_v4_v4(bufferIndex, srcFloatPxl);
00308                                                 add_v4_fl(bufferIndex,d);
00309                                                 F4TOCHAR4(bufferIndex, dstBytePxl);
00310                                         }
00311                                 }
00312                         } else {
00313                                 for (j = 0; j < h; j++){
00314                                         bufferIndex = buffer + w*j*4;
00315                                         dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
00316                                         srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
00317                                         for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
00318                                                 copy_v4_v4(bufferIndex, srcFloatPxl);
00319                                                 F4TOCHAR4(bufferIndex, dstBytePxl);
00320                                         }
00321                                 }
00322                         }
00323                 }
00324         }
00325         /* ensure user flag is reset */
00326         ibuf->userflags &= ~IB_RECT_INVALID;
00327 }
00328 
00329 static void imb_float_from_rect_nonlinear(struct ImBuf *ibuf, float *fbuf)
00330 {
00331         float *tof = fbuf;
00332         int i;
00333         unsigned char *to = (unsigned char *) ibuf->rect;
00334 
00335         for (i = ibuf->x * ibuf->y; i > 0; i--) 
00336         {
00337                 tof[0] = ((float)to[0])*(1.0f/255.0f);
00338                 tof[1] = ((float)to[1])*(1.0f/255.0f);
00339                 tof[2] = ((float)to[2])*(1.0f/255.0f);
00340                 tof[3] = ((float)to[3])*(1.0f/255.0f);
00341                 to += 4; 
00342                 tof += 4;
00343         }
00344 }
00345 
00346 
00347 static void imb_float_from_rect_linear(struct ImBuf *ibuf, float *fbuf)
00348 {
00349         float *tof = fbuf;
00350         int i;
00351         unsigned char *to = (unsigned char *) ibuf->rect;
00352 
00353         for (i = ibuf->x * ibuf->y; i > 0; i--) 
00354         {
00355                 tof[0] = srgb_to_linearrgb(((float)to[0])*(1.0f/255.0f));
00356                 tof[1] = srgb_to_linearrgb(((float)to[1])*(1.0f/255.0f));
00357                 tof[2] = srgb_to_linearrgb(((float)to[2])*(1.0f/255.0f));
00358                 tof[3] = ((float)to[3])*(1.0f/255.0f);
00359                 to += 4; 
00360                 tof += 4;
00361         }
00362 }
00363 
00364 void IMB_float_from_rect(struct ImBuf *ibuf)
00365 {
00366         /* quick method to convert byte to floatbuf */
00367         if(ibuf->rect==NULL) return;
00368         if(ibuf->rect_float==NULL) {
00369                 if (imb_addrectfloatImBuf(ibuf) == 0) return;
00370         }
00371         
00372         /* Float bufs should be stored linear */
00373 
00374         if (ibuf->profile != IB_PROFILE_NONE) {
00375                 /* if the image has been given a profile then we're working 
00376                  * with color management in mind, so convert it to linear space */
00377                 imb_float_from_rect_linear(ibuf, ibuf->rect_float);
00378         } else {
00379                 imb_float_from_rect_nonlinear(ibuf, ibuf->rect_float);
00380         }
00381 }
00382 
00383 /* no profile conversion */
00384 void IMB_float_from_rect_simple(struct ImBuf *ibuf)
00385 {
00386         if(ibuf->rect_float==NULL)
00387                 imb_addrectfloatImBuf(ibuf);
00388         imb_float_from_rect_nonlinear(ibuf, ibuf->rect_float);
00389 }
00390 
00391 void IMB_convert_profile(struct ImBuf *ibuf, int profile)
00392 {
00393         int ok= FALSE;
00394         int i;
00395 
00396         unsigned char *rct= (unsigned char *)ibuf->rect;
00397         float *rctf= ibuf->rect_float;
00398 
00399         if(ibuf->profile == profile)
00400                 return;
00401 
00402         if(ELEM(ibuf->profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* from */
00403                 if(profile == IB_PROFILE_LINEAR_RGB) { /* to */
00404                         if(ibuf->rect_float) {
00405                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) {
00406                                         rctf[0]= srgb_to_linearrgb(rctf[0]);
00407                                         rctf[1]= srgb_to_linearrgb(rctf[1]);
00408                                         rctf[2]= srgb_to_linearrgb(rctf[2]);
00409                                 }
00410                         }
00411                         if(ibuf->rect) {
00412                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) {
00413                                         rct[0]= (unsigned char)((srgb_to_linearrgb((float)rct[0]/255.0f) * 255.0f) + 0.5f);
00414                                         rct[1]= (unsigned char)((srgb_to_linearrgb((float)rct[1]/255.0f) * 255.0f) + 0.5f);
00415                                         rct[2]= (unsigned char)((srgb_to_linearrgb((float)rct[2]/255.0f) * 255.0f) + 0.5f);
00416                                 }
00417                         }
00418                         ok= TRUE;
00419                 }
00420         }
00421         else if (ibuf->profile == IB_PROFILE_LINEAR_RGB) { /* from */
00422                 if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* to */
00423                         if(ibuf->rect_float) {
00424                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) {
00425                                         rctf[0]= linearrgb_to_srgb(rctf[0]);
00426                                         rctf[1]= linearrgb_to_srgb(rctf[1]);
00427                                         rctf[2]= linearrgb_to_srgb(rctf[2]);
00428                                 }
00429                         }
00430                         if(ibuf->rect) {
00431                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) {
00432                                         rct[0]= (unsigned char)((linearrgb_to_srgb((float)rct[0]/255.0f) * 255.0f) + 0.5f);
00433                                         rct[1]= (unsigned char)((linearrgb_to_srgb((float)rct[1]/255.0f) * 255.0f) + 0.5f);
00434                                         rct[2]= (unsigned char)((linearrgb_to_srgb((float)rct[2]/255.0f) * 255.0f) + 0.5f);
00435                                 }
00436                         }
00437                         ok= TRUE;
00438                 }
00439         }
00440 
00441         if(ok==FALSE){
00442                 printf("IMB_convert_profile: failed profile conversion %d -> %d\n", ibuf->profile, profile);
00443                 return;
00444         }
00445 
00446         ibuf->profile= profile;
00447 }
00448 
00449 /* use when you need to get a buffer with a certain profile
00450  * if the return  */
00451 float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc)
00452 {
00453         /* stupid but it works like this everywhere now */
00454         const short is_lin_from= (ibuf->profile != IB_PROFILE_NONE);
00455         const short is_lin_to= (profile != IB_PROFILE_NONE);
00456 
00457         
00458         if(is_lin_from == is_lin_to) {
00459                 *alloc= 0;
00460 
00461                 /* simple case, just allocate the buffer and return */
00462                 if(ibuf->rect_float == NULL) {
00463                         IMB_float_from_rect(ibuf);
00464                 }
00465 
00466                 return ibuf->rect_float;
00467         }
00468         else {
00469                 /* conversion is needed, first check */
00470                 float *fbuf= MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "IMB_float_profile_ensure");
00471                 *alloc= 1;
00472 
00473                 if(ibuf->rect_float == NULL) {
00474                         if(is_lin_to) {
00475                                 imb_float_from_rect_linear(ibuf, fbuf);
00476                         }
00477                         else {
00478                                 imb_float_from_rect_nonlinear(ibuf, fbuf);
00479                         }
00480                 }
00481                 else {
00482                         if(is_lin_to) { /* lin -> nonlin */
00483                                 linearrgb_to_srgb_rgba_rgba_buf(fbuf, ibuf->rect_float, ibuf->x * ibuf->y);
00484                         }
00485                         else { /* nonlin -> lin */
00486                                 srgb_to_linearrgb_rgba_rgba_buf(fbuf, ibuf->rect_float, ibuf->x * ibuf->y);
00487                         }
00488                 }
00489 
00490                 return fbuf;
00491         }
00492 }
00493 
00494 
00495 /* no profile conversion */
00496 void IMB_color_to_bw(struct ImBuf *ibuf)
00497 {
00498         float *rctf= ibuf->rect_float;
00499         unsigned char *rct= (unsigned char *)ibuf->rect;
00500         int i;
00501         if(rctf) {
00502                 for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) {
00503                         rctf[0]= rctf[1]= rctf[2]= rgb_to_grayscale(rctf);
00504                 }
00505         }
00506 
00507         if(rct) {
00508                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) {
00509                         rct[0]= rct[1]= rct[2]= rgb_to_grayscale_byte(rct);
00510                 }
00511         }
00512 }