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