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