8f8c6311b309adc5813ab5932a829bf63e53b9fc
[blender.git] / source / blender / imbuf / intern / divers.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  * allocimbuf.c
27  *
28  */
29
30 /** \file blender/imbuf/intern/divers.c
31  *  \ingroup imbuf
32  */
33
34
35 #include "BLI_blenlib.h"
36 #include "BLI_rand.h"
37 #include "BLI_math.h"
38 #include "BLI_utildefines.h"
39
40 #include "imbuf.h"
41 #include "IMB_imbuf_types.h"
42 #include "IMB_imbuf.h"
43 #include "IMB_allocimbuf.h"
44
45 #include "MEM_guardedalloc.h"
46
47 /**************************** Interlace/Deinterlace **************************/
48
49 void IMB_de_interlace(ImBuf *ibuf)
50 {
51         ImBuf * tbuf1, * tbuf2;
52         
53         if (ibuf == NULL) return;
54         if (ibuf->flags & IB_fields) return;
55         ibuf->flags |= IB_fields;
56         
57         if (ibuf->rect) {
58                 /* make copies */
59                 tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
60                 tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
61                 
62                 ibuf->x *= 2;   
63                 IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
64                 IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
65         
66                 ibuf->x /= 2;
67                 IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
68                 IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y);
69                 
70                 IMB_freeImBuf(tbuf1);
71                 IMB_freeImBuf(tbuf2);
72         }
73         ibuf->y /= 2;
74 }
75
76 void IMB_interlace(ImBuf *ibuf)
77 {
78         ImBuf * tbuf1, * tbuf2;
79
80         if (ibuf == NULL) return;
81         ibuf->flags &= ~IB_fields;
82
83         ibuf->y *= 2;
84
85         if (ibuf->rect) {
86                 /* make copies */
87                 tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
88                 tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
89
90                 IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
91                 IMB_rectcpy(tbuf2, ibuf, 0, 0, 0, tbuf2->y, ibuf->x, ibuf->y);
92
93                 ibuf->x *= 2;
94                 IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
95                 IMB_rectcpy(ibuf, tbuf2, tbuf2->x, 0, 0, 0, tbuf2->x, tbuf2->y);
96                 ibuf->x /= 2;
97
98                 IMB_freeImBuf(tbuf1);
99                 IMB_freeImBuf(tbuf2);
100         }
101 }
102
103 /************************* Floyd-Steinberg dithering *************************/
104
105 typedef struct DitherContext {
106         int *error_buf, *e;
107         int v[4], v0[4], v1[4];
108         float f;
109 } DitherContext;
110
111 DitherContext *create_dither_context(int w, float factor)
112 {
113         DitherContext *di;
114         int i;
115         
116         di= MEM_callocN(sizeof(DitherContext), "dithering context");
117         di->f= factor / 16.0f;
118         di->error_buf= MEM_callocN(4*(w+1)*sizeof(int), "dithering error");
119         di->e= di->error_buf;
120
121         for (i=0; i<4; ++i)
122                 di->v[i]= di->v0[i]= di->v1[i]= 1024.0f*(BLI_frand()-0.5f);
123
124         return di;
125 }
126
127 static void clear_dither_context(DitherContext *di)
128 {
129         MEM_freeN(di->error_buf);
130         MEM_freeN(di);
131 }
132
133 static void dither_finish_row(DitherContext *di)
134 {
135         int i;
136
137         for (i=0; i<4; i++)
138                 di->v[i]= di->v0[i]= di->v1[i] = 0;
139
140         di->e= di->error_buf;
141 }
142
143 MINLINE unsigned char dither_value(unsigned short v_in, DitherContext *di, int i)
144 {
145         int dv, d2;
146         unsigned char v_out;
147
148         di->v[i] = v_in + (2*di->v[i] + di->e[4]) * di->f;
149         CLAMP(di->v[i], 0, 0xFF00);
150         v_out = USHORTTOUCHAR(di->v[i]);
151         di->v[i] -= v_out<<8;
152         dv = di->v[i];
153         d2 = di->v[i]<<1;
154         di->v[i] += d2;
155         *(di->e++) = di->v[i] + di->v0[i];
156         di->v[i] += d2;
157
158         di->v0[i] = di->v[i] + di->v1[i];
159         di->v1[i] = dv;
160         di->v[i] += d2;
161
162         return v_out;
163 }
164
165 /************************* Generic Buffer Conversion *************************/
166
167 MINLINE void ushort_to_byte_v4(uchar b[4], const unsigned short us[4])
168 {
169         b[0]= USHORTTOUCHAR(us[0]);
170         b[1]= USHORTTOUCHAR(us[1]);
171         b[2]= USHORTTOUCHAR(us[2]);
172         b[3]= USHORTTOUCHAR(us[3]);
173 }
174
175 MINLINE void ushort_to_byte_dither_v4(uchar b[4], const unsigned short us[4], DitherContext *di)
176 {
177         b[0]= dither_value(us[0], di, 0);
178         b[1]= dither_value(us[1], di, 1);
179         b[2]= dither_value(us[2], di, 2);
180         b[3]= dither_value(us[3], di, 3);
181 }
182
183 MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], DitherContext *di)
184 {
185         unsigned short us[4] = {FTOUSHORT(f[0]), FTOUSHORT(f[1]), FTOUSHORT(f[2]), FTOUSHORT(f[3])};
186         ushort_to_byte_dither_v4(b, us, di);
187 }
188
189 /* float to byte pixels, output 4-channel RGBA */
190 void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
191         int channels_from, float dither, int profile_to, int profile_from, int predivide,
192         int width, int height, int stride_to, int stride_from)
193 {
194         float tmp[4];
195         int x, y;
196         DitherContext *di;
197
198         /* we need valid profiles */
199         BLI_assert(profile_to != IB_PROFILE_NONE);
200         BLI_assert(profile_from != IB_PROFILE_NONE);
201
202         BLI_init_srgb_conversion();
203         if (dither)
204                 di= create_dither_context(width, dither);
205
206         for (y = 0; y < height; y++) {
207                 if (channels_from == 1) {
208                 /* single channel input */
209                         const float *from = rect_from + stride_from*y;
210                         uchar *to = rect_to + stride_to*y*4;
211
212                         for (x = 0; x < width; x++, from++, to+=4)
213                                 to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]);
214                 }
215                 else if (channels_from == 3) {
216                 /* RGB input */
217                         const float *from = rect_from + stride_from*y*3;
218                         uchar *to = rect_to + stride_to*y*4;
219
220                         if (profile_to == profile_from) {
221                                 /* no color space conversion */
222                                 for (x = 0; x < width; x++, from+=3, to+=4) {
223                                         rgb_float_to_uchar(to, from);
224                                         to[3] = 255;
225                                 }
226                         }
227                         else if (profile_to == IB_PROFILE_SRGB) {
228                                 /* convert from linear to sRGB */
229                                 for (x = 0; x < width; x++, from+=3, to+=4) {
230                                         linearrgb_to_srgb_v3_v3(tmp, from);
231                                         rgb_float_to_uchar(to, tmp);
232                                         to[3] = 255;
233                                 }
234                         }
235                         else if (profile_to == IB_PROFILE_LINEAR_RGB) {
236                                 /* convert from sRGB to linear */
237                                 for (x = 0; x < width; x++, from+=3, to+=4) {
238                                         srgb_to_linearrgb_v3_v3(tmp, from);
239                                         rgb_float_to_uchar(to, tmp);
240                                         to[3] = 255;
241                                 }
242                         }
243                 }
244                 else if (channels_from == 4) {
245                 /* RGBA input */
246                         const float *from = rect_from + stride_from*y*4;
247                         uchar *to = rect_to + stride_to*y*4;
248
249                         if (profile_to == profile_from) {
250                                 /* no color space conversion */
251                                 if (dither) {
252                                         for (x = 0; x < width; x++, from+=4, to+=4)
253                                                 float_to_byte_dither_v4(to, from, di);
254                                 }
255                                 else {
256                                         for (x = 0; x < width; x++, from+=4, to+=4)
257                                                 rgba_float_to_uchar(to, from);
258                                 }
259                         }
260                         else if (profile_to == IB_PROFILE_SRGB) {
261                                 /* convert from linear to sRGB */
262                                 unsigned short us[4];
263
264                                 if (dither && predivide) {
265                                         for (x = 0; x < width; x++, from+=4, to+=4) {
266                                                 linearrgb_to_srgb_ushort4_predivide(us, from);
267                                                 ushort_to_byte_dither_v4(to, us, di);
268                                         }
269                                 }
270                                 else if (dither) {
271                                         for (x = 0; x < width; x++, from+=4, to+=4) {
272                                                 linearrgb_to_srgb_ushort4(us, from);
273                                                 ushort_to_byte_dither_v4(to, us, di);
274                                         }
275                                 }
276                                 else if (predivide) {
277                                         for (x = 0; x < width; x++, from+=4, to+=4) {
278                                                 linearrgb_to_srgb_ushort4_predivide(us, from);
279                                                 ushort_to_byte_v4(to, us);
280                                         }
281                                 }
282                                 else {
283                                         for (x = 0; x < width; x++, from+=4, to+=4) {
284                                                 linearrgb_to_srgb_ushort4(us, from);
285                                                 ushort_to_byte_v4(to, us);
286                                         }
287                                 }
288                         }
289                         else if (profile_to == IB_PROFILE_LINEAR_RGB) {
290                                 /* convert from sRGB to linear */
291                                 if (dither && predivide) {
292                                         for (x = 0; x < width; x++, from+=4, to+=4) {
293                                                 srgb_to_linearrgb_predivide_v4(tmp, from);
294                                                 float_to_byte_dither_v4(to, tmp, di);
295                                         }
296                                 }
297                                 else if (dither) {
298                                         for (x = 0; x < width; x++, from+=4, to+=4) {
299                                                 srgb_to_linearrgb_v4(tmp, from);
300                                                 float_to_byte_dither_v4(to, tmp, di);
301                                         }
302                                 }
303                                 else if (predivide) {
304                                         for (x = 0; x < width; x++, from+=4, to+=4) {
305                                                 srgb_to_linearrgb_predivide_v4(tmp, from);
306                                                 rgba_float_to_uchar(to, tmp);
307                                         }
308                                 }
309                                 else {
310                                         for (x = 0; x < width; x++, from+=4, to+=4) {
311                                                 srgb_to_linearrgb_v4(tmp, from);
312                                                 rgba_float_to_uchar(to, tmp);
313                                         }
314                                 }
315                         }
316                 }
317
318                 if (dither)
319                         dither_finish_row(di);
320         }
321
322         if (dither)
323                 clear_dither_context(di);
324 }
325
326 /* byte to float pixels, input and output 4-channel RGBA  */
327 void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from,
328         int profile_to, int profile_from, int predivide,
329         int width, int height, int stride_to, int stride_from)
330 {
331         float tmp[4];
332         int x, y;
333
334         /* we need valid profiles */
335         BLI_assert(profile_to != IB_PROFILE_NONE);
336         BLI_assert(profile_from != IB_PROFILE_NONE);
337
338         BLI_init_srgb_conversion();
339
340         /* RGBA input */
341         for (y = 0; y < height; y++) {
342                 const uchar *from = rect_from + stride_from*y*4;
343                 float *to = rect_to + stride_to*y*4;
344
345                 if (profile_to == profile_from) {
346                         /* no color space conversion */
347                         for (x = 0; x < width; x++, from+=4, to+=4)
348                                 rgba_uchar_to_float(to, from);
349                 }
350                 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
351                         /* convert sRGB to linear */
352                         if (predivide) {
353                                 for (x = 0; x < width; x++, from+=4, to+=4) {
354                                         srgb_to_linearrgb_uchar4_predivide(to, from);
355                                 }
356                         }
357                         else {
358                                 for (x = 0; x < width; x++, from+=4, to+=4) {
359                                         srgb_to_linearrgb_uchar4(to, from);
360                                 }
361                         }
362                 }
363                 else if (profile_to == IB_PROFILE_SRGB) {
364                         /* convert linear to sRGB */
365                         if (predivide) {
366                                 for (x = 0; x < width; x++, from+=4, to+=4) {
367                                         rgba_uchar_to_float(tmp, from);
368                                         linearrgb_to_srgb_predivide_v4(to, tmp);
369                                 }
370                         }
371                         else {
372                                 for (x = 0; x < width; x++, from+=4, to+=4) {
373                                         rgba_uchar_to_float(tmp, from);
374                                         linearrgb_to_srgb_v4(to, tmp);
375                                 }
376                         }
377                 }
378         }
379 }
380
381 /* float to float pixels, output 4-channel RGBA */
382 void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
383         int channels_from, int profile_to, int profile_from, int predivide,
384         int width, int height, int stride_to, int stride_from)
385 {
386         int x, y;
387
388         /* we need valid profiles */
389         BLI_assert(profile_to != IB_PROFILE_NONE);
390         BLI_assert(profile_from != IB_PROFILE_NONE);
391
392         if (channels_from==1) {
393                 /* single channel input */
394                 for (y = 0; y < height; y++) {
395                         const float *from = rect_from + stride_from*y;
396                         float *to = rect_to + stride_to*y*4;
397
398                         for (x = 0; x < width; x++, from++, to+=4)
399                                 to[0] = to[1] = to[2] = to[3] = from[0];
400                 }
401         }
402         else if (channels_from == 3) {
403                 /* RGB input */
404                 for (y = 0; y < height; y++) {
405                         const float *from = rect_from + stride_from*y*3;
406                         float *to = rect_to + stride_to*y*4;
407
408                         if (profile_to == profile_from) {
409                                 /* no color space conversion */
410                                 for (x = 0; x < width; x++, from+=3, to+=4) {
411                                         copy_v3_v3(to, from);
412                                         to[3] = 1.0f;
413                                 }
414                         }
415                         else if (profile_to == IB_PROFILE_LINEAR_RGB) {
416                                 /* convert from sRGB to linear */
417                                 for (x = 0; x < width; x++, from+=3, to+=4) {
418                                         srgb_to_linearrgb_v3_v3(to, from);
419                                         to[3] = 1.0f;
420                                 }
421                         }
422                         else if (profile_to == IB_PROFILE_SRGB) {
423                                 /* convert from linear to sRGB */
424                                 for (x = 0; x < width; x++, from+=3, to+=4) {
425                                         linearrgb_to_srgb_v3_v3(to, from);
426                                         to[3] = 1.0f;
427                                 }
428                         }
429                 }
430         }
431         else if (channels_from == 4) {
432                 /* RGBA input */
433                 for (y = 0; y < height; y++) {
434                         const float *from = rect_from + stride_from*y*4;
435                         float *to = rect_to + stride_to*y*4;
436
437                         if (profile_to == profile_from) {
438                                 /* same profile, copy */
439                                 memcpy(to, from, sizeof(float)*4*width);
440                         }
441                         else if (profile_to == IB_PROFILE_LINEAR_RGB) {
442                                 /* convert to sRGB to linear */
443                                 if (predivide) {
444                                         for (x = 0; x < width; x++, from+=4, to+=4)
445                                                 srgb_to_linearrgb_predivide_v4(to, from);
446                                 }
447                                 else {
448                                         for (x = 0; x < width; x++, from+=4, to+=4)
449                                                 srgb_to_linearrgb_v4(to, from);
450                                 }
451                         }
452                         else if (profile_to == IB_PROFILE_SRGB) {
453                                 /* convert from linear to sRGB */
454                                 if (predivide) {
455                                         for (x = 0; x < width; x++, from+=4, to+=4)
456                                                 linearrgb_to_srgb_predivide_v4(to, from);
457                                 }
458                                 else {
459                                         for (x = 0; x < width; x++, from+=4, to+=4)
460                                                 linearrgb_to_srgb_v4(to, from);
461                                 }
462                         }
463                 }
464         }
465 }
466
467 /* byte to byte pixels, input and output 4-channel RGBA */
468 void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from,
469         int profile_to, int profile_from, int predivide,
470         int width, int height, int stride_to, int stride_from)
471 {
472         float tmp[4];
473         int x, y;
474
475         /* we need valid profiles */
476         BLI_assert(profile_to != IB_PROFILE_NONE);
477         BLI_assert(profile_from != IB_PROFILE_NONE);
478
479         /* always RGBA input */
480         for (y = 0; y < height; y++) {
481                 const uchar *from = rect_from + stride_from*y*4;
482                 uchar *to = rect_to + stride_to*y*4;
483
484                 if (profile_to == profile_from) {
485                         /* same profile, copy */
486                         memcpy(to, from, sizeof(uchar)*4*width);
487                 }
488                 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
489                         /* convert to sRGB to linear */
490                         if (predivide) {
491                                 for (x = 0; x < width; x++, from+=4, to+=4) {
492                                         rgba_uchar_to_float(tmp, from);
493                                         srgb_to_linearrgb_predivide_v4(tmp, tmp);
494                                         rgba_float_to_uchar(to, tmp);
495                                 }
496                         }
497                         else {
498                                 for (x = 0; x < width; x++, from+=4, to+=4) {
499                                         rgba_uchar_to_float(tmp, from);
500                                         srgb_to_linearrgb_v4(tmp, tmp);
501                                         rgba_float_to_uchar(to, tmp);
502                                 }
503                         }
504                 }
505                 else if (profile_to == IB_PROFILE_SRGB) {
506                         /* convert from linear to sRGB */
507                         if (predivide) {
508                                 for (x = 0; x < width; x++, from+=4, to+=4) {
509                                         rgba_uchar_to_float(tmp, from);
510                                         linearrgb_to_srgb_predivide_v4(tmp, tmp);
511                                         rgba_float_to_uchar(to, tmp);
512                                 }
513                         }
514                         else {
515                                 for (x = 0; x < width; x++, from+=4, to+=4) {
516                                         rgba_uchar_to_float(tmp, from);
517                                         linearrgb_to_srgb_v4(tmp, tmp);
518                                         rgba_float_to_uchar(to, tmp);
519                                 }
520                         }
521                 }
522         }
523 }
524
525 /****************************** ImBuf Conversion *****************************/
526
527 void IMB_rect_from_float(ImBuf *ibuf)
528 {
529         int predivide= (ibuf->flags & IB_cm_predivide);
530         int profile_from;
531
532         /* verify we have a float buffer */
533         if (ibuf->rect_float==NULL)
534                 return;
535
536         /* create byte rect if it didn't exist yet */
537         if (ibuf->rect==NULL)
538                 imb_addrectImBuf(ibuf);
539
540         /* determine profiles */
541         if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
542                 profile_from = IB_PROFILE_LINEAR_RGB;
543         else if (ELEM(ibuf->profile, IB_PROFILE_SRGB, IB_PROFILE_NONE))
544                 profile_from = IB_PROFILE_SRGB;
545         else
546                 BLI_assert(0);
547
548         /* do conversion */
549         IMB_buffer_byte_from_float((uchar*)ibuf->rect, ibuf->rect_float,
550                 ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide,
551                 ibuf->x, ibuf->y, ibuf->x, ibuf->x);
552
553         /* ensure user flag is reset */
554         ibuf->userflags &= ~IB_RECT_INVALID;
555 }
556
557 /* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */
558 void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w, int h)
559 {
560         float *rect_float;
561         uchar *rect_byte;
562         int predivide= (ibuf->flags & IB_cm_predivide);
563         int profile_from;
564
565         /* verify we have a float buffer */
566         if (ibuf->rect_float==NULL || buffer==NULL)
567                 return;
568
569         /* create byte rect if it didn't exist yet */
570         if (ibuf->rect==NULL)
571                 imb_addrectImBuf(ibuf);
572
573         /* determine profiles */
574         if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
575                 profile_from = IB_PROFILE_LINEAR_RGB;
576         else if (ELEM(ibuf->profile, IB_PROFILE_SRGB, IB_PROFILE_NONE))
577                 profile_from = IB_PROFILE_SRGB;
578         else
579                 BLI_assert(0);
580
581         /* do conversion */
582         rect_float= ibuf->rect_float + (x + y*ibuf->x)*ibuf->channels;
583         rect_byte= (uchar*)ibuf->rect + (x + y*ibuf->x)*4;
584
585         IMB_buffer_float_from_float(buffer, rect_float,
586                 ibuf->channels, IB_PROFILE_SRGB, profile_from, predivide,
587                 w, h, w, ibuf->x);
588
589         IMB_buffer_byte_from_float(rect_byte, buffer,
590                 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0,
591                 w, h, ibuf->x, w);
592
593         /* ensure user flag is reset */
594         ibuf->userflags &= ~IB_RECT_INVALID;
595 }
596
597 void IMB_float_from_rect(ImBuf *ibuf)
598 {
599         int predivide= (ibuf->flags & IB_cm_predivide);
600         int profile_from;
601
602         /* verify if we byte and float buffers */
603         if (ibuf->rect==NULL)
604                 return;
605
606         if (ibuf->rect_float==NULL)
607                 if (imb_addrectfloatImBuf(ibuf) == 0)
608                         return;
609         
610         /* determine profiles */
611         if (ibuf->profile == IB_PROFILE_NONE)
612                 profile_from = IB_PROFILE_LINEAR_RGB;
613         else
614                 profile_from = IB_PROFILE_SRGB;
615         
616         /* do conversion */
617         IMB_buffer_float_from_byte(ibuf->rect_float, (uchar*)ibuf->rect,
618                 IB_PROFILE_LINEAR_RGB, profile_from, predivide,
619                 ibuf->x, ibuf->y, ibuf->x, ibuf->x);
620 }
621
622 /* no profile conversion */
623 void IMB_float_from_rect_simple(ImBuf *ibuf)
624 {
625         int predivide= (ibuf->flags & IB_cm_predivide);
626
627         if (ibuf->rect_float==NULL)
628                 imb_addrectfloatImBuf(ibuf);
629
630         IMB_buffer_float_from_byte(ibuf->rect_float, (uchar*)ibuf->rect,
631                 IB_PROFILE_SRGB, IB_PROFILE_SRGB, predivide,
632                 ibuf->x, ibuf->y, ibuf->x, ibuf->x);
633 }
634
635 void IMB_convert_profile(ImBuf *ibuf, int profile)
636 {
637         int predivide= (ibuf->flags & IB_cm_predivide);
638         int profile_from, profile_to;
639
640         if (ibuf->profile == profile)
641                 return;
642
643         /* determine profiles */
644         if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
645                 profile_from = IB_PROFILE_LINEAR_RGB;
646         else if (ELEM(ibuf->profile, IB_PROFILE_SRGB, IB_PROFILE_NONE))
647                 profile_from = IB_PROFILE_SRGB;
648         else {
649                 BLI_assert(0);
650                 profile_from = IB_PROFILE_SRGB; /* dummy, should never happen */
651         }
652
653         if (profile == IB_PROFILE_LINEAR_RGB)
654                 profile_to = IB_PROFILE_LINEAR_RGB;
655         else if (ELEM(profile, IB_PROFILE_SRGB, IB_PROFILE_NONE))
656                 profile_to = IB_PROFILE_SRGB;
657         else {
658                 BLI_assert(0);
659                 profile_to = IB_PROFILE_SRGB; /* dummy, should never happen */
660         }
661         
662         /* do conversion */
663         if (ibuf->rect_float) {
664                 IMB_buffer_float_from_float(ibuf->rect_float, ibuf->rect_float,
665                         4, profile_to, profile_from, predivide,
666                         ibuf->x, ibuf->y, ibuf->x, ibuf->x);
667         }
668
669         if (ibuf->rect) {
670                 IMB_buffer_byte_from_byte((uchar*)ibuf->rect, (uchar*)ibuf->rect,
671                         profile_to, profile_from, predivide,
672                         ibuf->x, ibuf->y, ibuf->x, ibuf->x);
673         }
674
675         /* set new profile */
676         ibuf->profile= profile;
677 }
678
679 /* use when you need to get a buffer with a certain profile
680  * if the return  */
681 float *IMB_float_profile_ensure(ImBuf *ibuf, int profile, int *alloc)
682 {
683         int predivide= (ibuf->flags & IB_cm_predivide);
684         int profile_from, profile_to;
685
686         /* determine profiles */
687         if (ibuf->profile == IB_PROFILE_NONE)
688                 profile_from = IB_PROFILE_LINEAR_RGB;
689         else
690                 profile_from = IB_PROFILE_SRGB;
691
692         if (profile == IB_PROFILE_NONE)
693                 profile_to = IB_PROFILE_LINEAR_RGB;
694         else
695                 profile_to = IB_PROFILE_SRGB;
696         
697         if (profile_from == profile_to) {
698                 /* simple case, just allocate the buffer and return */
699                 *alloc= 0;
700
701                 if (ibuf->rect_float == NULL)
702                         IMB_float_from_rect(ibuf);
703
704                 return ibuf->rect_float;
705         }
706         else {
707                 /* conversion is needed, first check */
708                 float *fbuf= MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "IMB_float_profile_ensure");
709                 *alloc= 1;
710
711                 if (ibuf->rect_float == NULL) {
712                         IMB_buffer_float_from_byte(fbuf, (uchar*)ibuf->rect,
713                                 profile_to, profile_from, predivide,
714                                 ibuf->x, ibuf->y, ibuf->x, ibuf->x);
715                 }
716                 else {
717                         IMB_buffer_float_from_float(fbuf, ibuf->rect_float,
718                                 4, profile_to, profile_from, predivide,
719                                 ibuf->x, ibuf->y, ibuf->x, ibuf->x);
720                 }
721
722                 return fbuf;
723         }
724 }
725
726 /**************************** Color to Grayscale *****************************/
727
728 /* no profile conversion */
729 void IMB_color_to_bw(ImBuf *ibuf)
730 {
731         float *rctf= ibuf->rect_float;
732         uchar *rct= (uchar*)ibuf->rect;
733         int i;
734
735         if (rctf) {
736                 for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4)
737                         rctf[0]= rctf[1]= rctf[2]= rgb_to_grayscale(rctf);
738         }
739
740         if (rct) {
741                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4)
742                         rct[0]= rct[1]= rct[2]= rgb_to_grayscale_byte(rct);
743         }
744 }
745
746 void IMB_buffer_float_clamp(float *buf, int width, int height)
747 {
748         int i, total = width*height*4;
749         for (i = 0; i < total; i++) {
750                 buf[i] = MIN2(1.0, buf[i]);
751         }
752 }
753
754 /**************************** alter saturation *****************************/
755
756 void IMB_saturation(ImBuf * ibuf, float sat)
757 {
758         int i;
759         unsigned char *rct= (unsigned char *)ibuf->rect;
760         float *rctf= ibuf->rect_float;
761         float hsv[3];
762
763         if (rct) {
764                 float rgb[3];
765                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) {
766                         rgb_uchar_to_float(rgb, rct);
767                         rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
768                         hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb+1, rgb+2);
769                         rgb_float_to_uchar(rct, rgb);
770                 }
771         }
772
773         if (rctf) {
774                 for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) {
775                         rgb_to_hsv(rctf[0], rctf[1], rctf[2], hsv, hsv+1, hsv+2);
776                         hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rctf, rctf+1, rctf+2);
777                 }
778         }
779 }