535d2e9512292c14b0253eb25d26f70bec5fd80b
[blender.git] / source / blender / imbuf / intern / divers.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  * allocimbuf.c
19  */
20
21 /** \file
22  * \ingroup imbuf
23  */
24
25 #include "BLI_math.h"
26 #include "BLI_utildefines.h"
27
28 #include "imbuf.h"
29 #include "IMB_imbuf_types.h"
30 #include "IMB_imbuf.h"
31 #include "IMB_filter.h"
32
33 #include "IMB_colormanagement.h"
34 #include "IMB_colormanagement_intern.h"
35
36 #include "MEM_guardedalloc.h"
37
38 /************************* Floyd-Steinberg dithering *************************/
39
40 typedef struct DitherContext {
41   float dither;
42 } DitherContext;
43
44 static DitherContext *create_dither_context(float dither)
45 {
46   DitherContext *di;
47
48   di = MEM_mallocN(sizeof(DitherContext), "dithering context");
49   di->dither = dither;
50
51   return di;
52 }
53
54 static void clear_dither_context(DitherContext *di)
55 {
56   MEM_freeN(di);
57 }
58
59 /************************* Generic Buffer Conversion *************************/
60
61 MINLINE void ushort_to_byte_v4(uchar b[4], const unsigned short us[4])
62 {
63   b[0] = unit_ushort_to_uchar(us[0]);
64   b[1] = unit_ushort_to_uchar(us[1]);
65   b[2] = unit_ushort_to_uchar(us[2]);
66   b[3] = unit_ushort_to_uchar(us[3]);
67 }
68
69 MINLINE unsigned char ftochar(float value)
70 {
71   return unit_float_to_uchar_clamp(value);
72 }
73
74 MINLINE void ushort_to_byte_dither_v4(
75     uchar b[4], const unsigned short us[4], DitherContext *di, float s, float t)
76 {
77 #define USHORTTOFLOAT(val) ((float)val / 65535.0f)
78   float dither_value = dither_random_value(s, t) * 0.005f * di->dither;
79
80   b[0] = ftochar(dither_value + USHORTTOFLOAT(us[0]));
81   b[1] = ftochar(dither_value + USHORTTOFLOAT(us[1]));
82   b[2] = ftochar(dither_value + USHORTTOFLOAT(us[2]));
83   b[3] = unit_ushort_to_uchar(us[3]);
84
85 #undef USHORTTOFLOAT
86 }
87
88 MINLINE void float_to_byte_dither_v4(
89     uchar b[4], const float f[4], DitherContext *di, float s, float t)
90 {
91   float dither_value = dither_random_value(s, t) * 0.005f * di->dither;
92
93   b[0] = ftochar(dither_value + f[0]);
94   b[1] = ftochar(dither_value + f[1]);
95   b[2] = ftochar(dither_value + f[2]);
96   b[3] = unit_float_to_uchar_clamp(f[3]);
97 }
98
99 /* float to byte pixels, output 4-channel RGBA */
100 void IMB_buffer_byte_from_float(uchar *rect_to,
101                                 const float *rect_from,
102                                 int channels_from,
103                                 float dither,
104                                 int profile_to,
105                                 int profile_from,
106                                 bool predivide,
107                                 int width,
108                                 int height,
109                                 int stride_to,
110                                 int stride_from)
111 {
112   float tmp[4];
113   int x, y;
114   DitherContext *di = NULL;
115   float inv_width = 1.0f / width;
116   float inv_height = 1.0f / height;
117
118   /* we need valid profiles */
119   BLI_assert(profile_to != IB_PROFILE_NONE);
120   BLI_assert(profile_from != IB_PROFILE_NONE);
121
122   if (dither)
123     di = create_dither_context(dither);
124
125   for (y = 0; y < height; y++) {
126     float t = y * inv_height;
127
128     if (channels_from == 1) {
129       /* single channel input */
130       const float *from = rect_from + ((size_t)stride_from) * y;
131       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
132
133       for (x = 0; x < width; x++, from++, to += 4)
134         to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
135     }
136     else if (channels_from == 3) {
137       /* RGB input */
138       const float *from = rect_from + ((size_t)stride_from) * y * 3;
139       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
140
141       if (profile_to == profile_from) {
142         /* no color space conversion */
143         for (x = 0; x < width; x++, from += 3, to += 4) {
144           rgb_float_to_uchar(to, from);
145           to[3] = 255;
146         }
147       }
148       else if (profile_to == IB_PROFILE_SRGB) {
149         /* convert from linear to sRGB */
150         for (x = 0; x < width; x++, from += 3, to += 4) {
151           linearrgb_to_srgb_v3_v3(tmp, from);
152           rgb_float_to_uchar(to, tmp);
153           to[3] = 255;
154         }
155       }
156       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
157         /* convert from sRGB to linear */
158         for (x = 0; x < width; x++, from += 3, to += 4) {
159           srgb_to_linearrgb_v3_v3(tmp, from);
160           rgb_float_to_uchar(to, tmp);
161           to[3] = 255;
162         }
163       }
164     }
165     else if (channels_from == 4) {
166       /* RGBA input */
167       const float *from = rect_from + ((size_t)stride_from) * y * 4;
168       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
169
170       if (profile_to == profile_from) {
171         float straight[4];
172
173         /* no color space conversion */
174         if (dither && predivide) {
175           for (x = 0; x < width; x++, from += 4, to += 4) {
176             premul_to_straight_v4_v4(straight, from);
177             float_to_byte_dither_v4(to, straight, di, (float)x * inv_width, t);
178           }
179         }
180         else if (dither) {
181           for (x = 0; x < width; x++, from += 4, to += 4)
182             float_to_byte_dither_v4(to, from, di, (float)x * inv_width, t);
183         }
184         else if (predivide) {
185           for (x = 0; x < width; x++, from += 4, to += 4) {
186             premul_to_straight_v4_v4(straight, from);
187             rgba_float_to_uchar(to, straight);
188           }
189         }
190         else {
191           for (x = 0; x < width; x++, from += 4, to += 4)
192             rgba_float_to_uchar(to, from);
193         }
194       }
195       else if (profile_to == IB_PROFILE_SRGB) {
196         /* convert from linear to sRGB */
197         unsigned short us[4];
198         float straight[4];
199
200         if (dither && predivide) {
201           for (x = 0; x < width; x++, from += 4, to += 4) {
202             premul_to_straight_v4_v4(straight, from);
203             linearrgb_to_srgb_ushort4(us, from);
204             ushort_to_byte_dither_v4(to, us, di, (float)x * inv_width, t);
205           }
206         }
207         else if (dither) {
208           for (x = 0; x < width; x++, from += 4, to += 4) {
209             linearrgb_to_srgb_ushort4(us, from);
210             ushort_to_byte_dither_v4(to, us, di, (float)x * inv_width, t);
211           }
212         }
213         else if (predivide) {
214           for (x = 0; x < width; x++, from += 4, to += 4) {
215             premul_to_straight_v4_v4(straight, from);
216             linearrgb_to_srgb_ushort4(us, from);
217             ushort_to_byte_v4(to, us);
218           }
219         }
220         else {
221           for (x = 0; x < width; x++, from += 4, to += 4) {
222             linearrgb_to_srgb_ushort4(us, from);
223             ushort_to_byte_v4(to, us);
224           }
225         }
226       }
227       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
228         /* convert from sRGB to linear */
229         if (dither && predivide) {
230           for (x = 0; x < width; x++, from += 4, to += 4) {
231             srgb_to_linearrgb_predivide_v4(tmp, from);
232             float_to_byte_dither_v4(to, tmp, di, (float)x * inv_width, t);
233           }
234         }
235         else if (dither) {
236           for (x = 0; x < width; x++, from += 4, to += 4) {
237             srgb_to_linearrgb_v4(tmp, from);
238             float_to_byte_dither_v4(to, tmp, di, (float)x * inv_width, t);
239           }
240         }
241         else if (predivide) {
242           for (x = 0; x < width; x++, from += 4, to += 4) {
243             srgb_to_linearrgb_predivide_v4(tmp, from);
244             rgba_float_to_uchar(to, tmp);
245           }
246         }
247         else {
248           for (x = 0; x < width; x++, from += 4, to += 4) {
249             srgb_to_linearrgb_v4(tmp, from);
250             rgba_float_to_uchar(to, tmp);
251           }
252         }
253       }
254     }
255   }
256
257   if (dither)
258     clear_dither_context(di);
259 }
260
261 /* float to byte pixels, output 4-channel RGBA */
262 void IMB_buffer_byte_from_float_mask(uchar *rect_to,
263                                      const float *rect_from,
264                                      int channels_from,
265                                      float dither,
266                                      bool predivide,
267                                      int width,
268                                      int height,
269                                      int stride_to,
270                                      int stride_from,
271                                      char *mask)
272 {
273   int x, y;
274   DitherContext *di = NULL;
275   float inv_width = 1.0f / width, inv_height = 1.0f / height;
276
277   if (dither)
278     di = create_dither_context(dither);
279
280   for (y = 0; y < height; y++) {
281     float t = y * inv_height;
282
283     if (channels_from == 1) {
284       /* single channel input */
285       const float *from = rect_from + ((size_t)stride_from) * y;
286       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
287
288       for (x = 0; x < width; x++, from++, to += 4)
289         if (*mask++ == FILTER_MASK_USED)
290           to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
291     }
292     else if (channels_from == 3) {
293       /* RGB input */
294       const float *from = rect_from + ((size_t)stride_from) * y * 3;
295       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
296
297       for (x = 0; x < width; x++, from += 3, to += 4) {
298         if (*mask++ == FILTER_MASK_USED) {
299           rgb_float_to_uchar(to, from);
300           to[3] = 255;
301         }
302       }
303     }
304     else if (channels_from == 4) {
305       /* RGBA input */
306       const float *from = rect_from + ((size_t)stride_from) * y * 4;
307       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
308
309       float straight[4];
310
311       if (dither && predivide) {
312         for (x = 0; x < width; x++, from += 4, to += 4) {
313           if (*mask++ == FILTER_MASK_USED) {
314             premul_to_straight_v4_v4(straight, from);
315             float_to_byte_dither_v4(to, straight, di, (float)x * inv_width, t);
316           }
317         }
318       }
319       else if (dither) {
320         for (x = 0; x < width; x++, from += 4, to += 4)
321           if (*mask++ == FILTER_MASK_USED)
322             float_to_byte_dither_v4(to, from, di, (float)x * inv_width, t);
323       }
324       else if (predivide) {
325         for (x = 0; x < width; x++, from += 4, to += 4) {
326           if (*mask++ == FILTER_MASK_USED) {
327             premul_to_straight_v4_v4(straight, from);
328             rgba_float_to_uchar(to, straight);
329           }
330         }
331       }
332       else {
333         for (x = 0; x < width; x++, from += 4, to += 4)
334           if (*mask++ == FILTER_MASK_USED)
335             rgba_float_to_uchar(to, from);
336       }
337     }
338   }
339
340   if (dither)
341     clear_dither_context(di);
342 }
343
344 /* byte to float pixels, input and output 4-channel RGBA  */
345 void IMB_buffer_float_from_byte(float *rect_to,
346                                 const uchar *rect_from,
347                                 int profile_to,
348                                 int profile_from,
349                                 bool predivide,
350                                 int width,
351                                 int height,
352                                 int stride_to,
353                                 int stride_from)
354 {
355   float tmp[4];
356   int x, y;
357
358   /* we need valid profiles */
359   BLI_assert(profile_to != IB_PROFILE_NONE);
360   BLI_assert(profile_from != IB_PROFILE_NONE);
361
362   /* RGBA input */
363   for (y = 0; y < height; y++) {
364     const uchar *from = rect_from + stride_from * y * 4;
365     float *to = rect_to + ((size_t)stride_to) * y * 4;
366
367     if (profile_to == profile_from) {
368       /* no color space conversion */
369       for (x = 0; x < width; x++, from += 4, to += 4)
370         rgba_uchar_to_float(to, from);
371     }
372     else if (profile_to == IB_PROFILE_LINEAR_RGB) {
373       /* convert sRGB to linear */
374       if (predivide) {
375         for (x = 0; x < width; x++, from += 4, to += 4) {
376           srgb_to_linearrgb_uchar4_predivide(to, from);
377         }
378       }
379       else {
380         for (x = 0; x < width; x++, from += 4, to += 4) {
381           srgb_to_linearrgb_uchar4(to, from);
382         }
383       }
384     }
385     else if (profile_to == IB_PROFILE_SRGB) {
386       /* convert linear to sRGB */
387       if (predivide) {
388         for (x = 0; x < width; x++, from += 4, to += 4) {
389           rgba_uchar_to_float(tmp, from);
390           linearrgb_to_srgb_predivide_v4(to, tmp);
391         }
392       }
393       else {
394         for (x = 0; x < width; x++, from += 4, to += 4) {
395           rgba_uchar_to_float(tmp, from);
396           linearrgb_to_srgb_v4(to, tmp);
397         }
398       }
399     }
400   }
401 }
402
403 /* float to float pixels, output 4-channel RGBA */
404 void IMB_buffer_float_from_float(float *rect_to,
405                                  const float *rect_from,
406                                  int channels_from,
407                                  int profile_to,
408                                  int profile_from,
409                                  bool predivide,
410                                  int width,
411                                  int height,
412                                  int stride_to,
413                                  int stride_from)
414 {
415   int x, y;
416
417   /* we need valid profiles */
418   BLI_assert(profile_to != IB_PROFILE_NONE);
419   BLI_assert(profile_from != IB_PROFILE_NONE);
420
421   if (channels_from == 1) {
422     /* single channel input */
423     for (y = 0; y < height; y++) {
424       const float *from = rect_from + ((size_t)stride_from) * y;
425       float *to = rect_to + ((size_t)stride_to) * y * 4;
426
427       for (x = 0; x < width; x++, from++, to += 4)
428         to[0] = to[1] = to[2] = to[3] = from[0];
429     }
430   }
431   else if (channels_from == 3) {
432     /* RGB input */
433     for (y = 0; y < height; y++) {
434       const float *from = rect_from + ((size_t)stride_from) * y * 3;
435       float *to = rect_to + ((size_t)stride_to) * y * 4;
436
437       if (profile_to == profile_from) {
438         /* no color space conversion */
439         for (x = 0; x < width; x++, from += 3, to += 4) {
440           copy_v3_v3(to, from);
441           to[3] = 1.0f;
442         }
443       }
444       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
445         /* convert from sRGB to linear */
446         for (x = 0; x < width; x++, from += 3, to += 4) {
447           srgb_to_linearrgb_v3_v3(to, from);
448           to[3] = 1.0f;
449         }
450       }
451       else if (profile_to == IB_PROFILE_SRGB) {
452         /* convert from linear to sRGB */
453         for (x = 0; x < width; x++, from += 3, to += 4) {
454           linearrgb_to_srgb_v3_v3(to, from);
455           to[3] = 1.0f;
456         }
457       }
458     }
459   }
460   else if (channels_from == 4) {
461     /* RGBA input */
462     for (y = 0; y < height; y++) {
463       const float *from = rect_from + ((size_t)stride_from) * y * 4;
464       float *to = rect_to + ((size_t)stride_to) * y * 4;
465
466       if (profile_to == profile_from) {
467         /* same profile, copy */
468         memcpy(to, from, sizeof(float) * ((size_t)4) * width);
469       }
470       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
471         /* convert to sRGB to linear */
472         if (predivide) {
473           for (x = 0; x < width; x++, from += 4, to += 4)
474             srgb_to_linearrgb_predivide_v4(to, from);
475         }
476         else {
477           for (x = 0; x < width; x++, from += 4, to += 4)
478             srgb_to_linearrgb_v4(to, from);
479         }
480       }
481       else if (profile_to == IB_PROFILE_SRGB) {
482         /* convert from linear to sRGB */
483         if (predivide) {
484           for (x = 0; x < width; x++, from += 4, to += 4)
485             linearrgb_to_srgb_predivide_v4(to, from);
486         }
487         else {
488           for (x = 0; x < width; x++, from += 4, to += 4)
489             linearrgb_to_srgb_v4(to, from);
490         }
491       }
492     }
493   }
494 }
495
496 typedef struct FloatToFloatThreadData {
497   float *rect_to;
498   const float *rect_from;
499   int channels_from;
500   int profile_to;
501   int profile_from;
502   bool predivide;
503   int width;
504   int stride_to;
505   int stride_from;
506 } FloatToFloatThreadData;
507
508 static void imb_buffer_float_from_float_thread_do(void *data_v,
509                                                   int start_scanline,
510                                                   int num_scanlines)
511 {
512   FloatToFloatThreadData *data = (FloatToFloatThreadData *)data_v;
513   size_t offset_from = ((size_t)start_scanline) * data->stride_from * data->channels_from;
514   size_t offset_to = ((size_t)start_scanline) * data->stride_to * data->channels_from;
515   IMB_buffer_float_from_float(data->rect_to + offset_to,
516                               data->rect_from + offset_from,
517                               data->channels_from,
518                               data->profile_to,
519                               data->profile_from,
520                               data->predivide,
521                               data->width,
522                               num_scanlines,
523                               data->stride_to,
524                               data->stride_from);
525 }
526
527 void IMB_buffer_float_from_float_threaded(float *rect_to,
528                                           const float *rect_from,
529                                           int channels_from,
530                                           int profile_to,
531                                           int profile_from,
532                                           bool predivide,
533                                           int width,
534                                           int height,
535                                           int stride_to,
536                                           int stride_from)
537 {
538   if (((size_t)width) * height < 64 * 64) {
539     IMB_buffer_float_from_float(rect_to,
540                                 rect_from,
541                                 channels_from,
542                                 profile_to,
543                                 profile_from,
544                                 predivide,
545                                 width,
546                                 height,
547                                 stride_to,
548                                 stride_from);
549   }
550   else {
551     FloatToFloatThreadData data;
552     data.rect_to = rect_to;
553     data.rect_from = rect_from;
554     data.channels_from = channels_from;
555     data.profile_to = profile_to;
556     data.profile_from = profile_from;
557     data.predivide = predivide;
558     data.width = width;
559     data.stride_to = stride_to;
560     data.stride_from = stride_from;
561     IMB_processor_apply_threaded_scanlines(height, imb_buffer_float_from_float_thread_do, &data);
562   }
563 }
564
565 /* float to float pixels, output 4-channel RGBA */
566 void IMB_buffer_float_from_float_mask(float *rect_to,
567                                       const float *rect_from,
568                                       int channels_from,
569                                       int width,
570                                       int height,
571                                       int stride_to,
572                                       int stride_from,
573                                       char *mask)
574 {
575   int x, y;
576
577   if (channels_from == 1) {
578     /* single channel input */
579     for (y = 0; y < height; y++) {
580       const float *from = rect_from + ((size_t)stride_from) * y;
581       float *to = rect_to + ((size_t)stride_to) * y * 4;
582
583       for (x = 0; x < width; x++, from++, to += 4)
584         if (*mask++ == FILTER_MASK_USED)
585           to[0] = to[1] = to[2] = to[3] = from[0];
586     }
587   }
588   else if (channels_from == 3) {
589     /* RGB input */
590     for (y = 0; y < height; y++) {
591       const float *from = rect_from + ((size_t)stride_from) * y * 3;
592       float *to = rect_to + ((size_t)stride_to) * y * 4;
593
594       for (x = 0; x < width; x++, from += 3, to += 4) {
595         if (*mask++ == FILTER_MASK_USED) {
596           copy_v3_v3(to, from);
597           to[3] = 1.0f;
598         }
599       }
600     }
601   }
602   else if (channels_from == 4) {
603     /* RGBA input */
604     for (y = 0; y < height; y++) {
605       const float *from = rect_from + ((size_t)stride_from) * y * 4;
606       float *to = rect_to + ((size_t)stride_to) * y * 4;
607
608       for (x = 0; x < width; x++, from += 4, to += 4)
609         if (*mask++ == FILTER_MASK_USED)
610           copy_v4_v4(to, from);
611     }
612   }
613 }
614
615 /* byte to byte pixels, input and output 4-channel RGBA */
616 void IMB_buffer_byte_from_byte(uchar *rect_to,
617                                const uchar *rect_from,
618                                int profile_to,
619                                int profile_from,
620                                bool predivide,
621                                int width,
622                                int height,
623                                int stride_to,
624                                int stride_from)
625 {
626   float tmp[4];
627   int x, y;
628
629   /* we need valid profiles */
630   BLI_assert(profile_to != IB_PROFILE_NONE);
631   BLI_assert(profile_from != IB_PROFILE_NONE);
632
633   /* always RGBA input */
634   for (y = 0; y < height; y++) {
635     const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
636     uchar *to = rect_to + ((size_t)stride_to) * y * 4;
637
638     if (profile_to == profile_from) {
639       /* same profile, copy */
640       memcpy(to, from, sizeof(uchar) * 4 * width);
641     }
642     else if (profile_to == IB_PROFILE_LINEAR_RGB) {
643       /* convert to sRGB to linear */
644       if (predivide) {
645         for (x = 0; x < width; x++, from += 4, to += 4) {
646           rgba_uchar_to_float(tmp, from);
647           srgb_to_linearrgb_predivide_v4(tmp, tmp);
648           rgba_float_to_uchar(to, tmp);
649         }
650       }
651       else {
652         for (x = 0; x < width; x++, from += 4, to += 4) {
653           rgba_uchar_to_float(tmp, from);
654           srgb_to_linearrgb_v4(tmp, tmp);
655           rgba_float_to_uchar(to, tmp);
656         }
657       }
658     }
659     else if (profile_to == IB_PROFILE_SRGB) {
660       /* convert from linear to sRGB */
661       if (predivide) {
662         for (x = 0; x < width; x++, from += 4, to += 4) {
663           rgba_uchar_to_float(tmp, from);
664           linearrgb_to_srgb_predivide_v4(tmp, tmp);
665           rgba_float_to_uchar(to, tmp);
666         }
667       }
668       else {
669         for (x = 0; x < width; x++, from += 4, to += 4) {
670           rgba_uchar_to_float(tmp, from);
671           linearrgb_to_srgb_v4(tmp, tmp);
672           rgba_float_to_uchar(to, tmp);
673         }
674       }
675     }
676   }
677 }
678
679 /****************************** ImBuf Conversion *****************************/
680
681 void IMB_rect_from_float(ImBuf *ibuf)
682 {
683   float *buffer;
684   const char *from_colorspace;
685
686   /* verify we have a float buffer */
687   if (ibuf->rect_float == NULL)
688     return;
689
690   /* create byte rect if it didn't exist yet */
691   if (ibuf->rect == NULL) {
692     if (imb_addrectImBuf(ibuf) == 0)
693       return;
694   }
695
696   if (ibuf->float_colorspace == NULL)
697     from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
698   else
699     from_colorspace = ibuf->float_colorspace->name;
700
701   buffer = MEM_dupallocN(ibuf->rect_float);
702
703   /* first make float buffer in byte space */
704   IMB_colormanagement_transform(buffer,
705                                 ibuf->x,
706                                 ibuf->y,
707                                 ibuf->channels,
708                                 from_colorspace,
709                                 ibuf->rect_colorspace->name,
710                                 true);
711
712   /* convert from float's premul alpha to byte's straight alpha */
713   IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y);
714
715   /* convert float to byte */
716   IMB_buffer_byte_from_float((unsigned char *)ibuf->rect,
717                              buffer,
718                              ibuf->channels,
719                              ibuf->dither,
720                              IB_PROFILE_SRGB,
721                              IB_PROFILE_SRGB,
722                              false,
723                              ibuf->x,
724                              ibuf->y,
725                              ibuf->x,
726                              ibuf->x);
727
728   MEM_freeN(buffer);
729
730   /* ensure user flag is reset */
731   ibuf->userflags &= ~IB_RECT_INVALID;
732 }
733
734 typedef struct PartialThreadData {
735   ImBuf *ibuf;
736   float *buffer;
737   uchar *rect_byte;
738   const float *rect_float;
739   int width;
740   bool is_data;
741 } PartialThreadData;
742
743 static void partial_rect_from_float_slice(float *buffer,
744                                           uchar *rect_byte,
745                                           ImBuf *ibuf,
746                                           const float *rect_float,
747                                           const int w,
748                                           const int h,
749                                           const bool is_data)
750 {
751   const int profile_from = IB_PROFILE_LINEAR_RGB;
752   if (is_data) {
753     /* exception for non-color data, just copy float */
754     IMB_buffer_float_from_float(buffer,
755                                 rect_float,
756                                 ibuf->channels,
757                                 IB_PROFILE_LINEAR_RGB,
758                                 IB_PROFILE_LINEAR_RGB,
759                                 0,
760                                 w,
761                                 h,
762                                 w,
763                                 ibuf->x);
764
765     /* and do color space conversion to byte */
766     IMB_buffer_byte_from_float(rect_byte,
767                                rect_float,
768                                4,
769                                ibuf->dither,
770                                IB_PROFILE_SRGB,
771                                profile_from,
772                                true,
773                                w,
774                                h,
775                                ibuf->x,
776                                w);
777   }
778   else {
779     IMB_buffer_float_from_float(
780         buffer, rect_float, ibuf->channels, IB_PROFILE_SRGB, profile_from, true, w, h, w, ibuf->x);
781
782     IMB_buffer_float_unpremultiply(buffer, w, h);
783     /* XXX: need to convert to image buffer's rect space */
784     IMB_buffer_byte_from_float(
785         rect_byte, buffer, 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0, w, h, ibuf->x, w);
786   }
787 }
788
789 static void partial_rect_from_float_thread_do(void *data_v, int start_scanline, int num_scanlines)
790 {
791   PartialThreadData *data = (PartialThreadData *)data_v;
792   ImBuf *ibuf = data->ibuf;
793   size_t global_offset = ((size_t)ibuf->x) * start_scanline;
794   size_t local_offset = ((size_t)data->width) * start_scanline;
795   partial_rect_from_float_slice(data->buffer + local_offset * ibuf->channels,
796                                 data->rect_byte + global_offset * 4,
797                                 ibuf,
798                                 data->rect_float + global_offset * ibuf->channels,
799                                 data->width,
800                                 num_scanlines,
801                                 data->is_data);
802 }
803
804 /**
805  * Converts from linear float to sRGB byte for part of the texture,
806  * buffer will hold the changed part.
807  */
808 void IMB_partial_rect_from_float(
809     ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data)
810 {
811   const float *rect_float;
812   uchar *rect_byte;
813
814   /* verify we have a float buffer */
815   if (ibuf->rect_float == NULL || buffer == NULL)
816     return;
817
818   /* create byte rect if it didn't exist yet */
819   if (ibuf->rect == NULL)
820     imb_addrectImBuf(ibuf);
821
822   /* do conversion */
823   rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels;
824   rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4;
825
826   if (((size_t)w) * h < 64 * 64) {
827     partial_rect_from_float_slice(buffer, rect_byte, ibuf, rect_float, w, h, is_data);
828   }
829   else {
830     PartialThreadData data;
831     data.ibuf = ibuf;
832     data.buffer = buffer;
833     data.rect_byte = rect_byte;
834     data.rect_float = rect_float;
835     data.width = w;
836     data.is_data = is_data;
837     IMB_processor_apply_threaded_scanlines(h, partial_rect_from_float_thread_do, &data);
838   }
839
840   /* ensure user flag is reset */
841   ibuf->userflags &= ~IB_RECT_INVALID;
842 }
843
844 void IMB_float_from_rect(ImBuf *ibuf)
845 {
846   float *rect_float;
847
848   /* verify if we byte and float buffers */
849   if (ibuf->rect == NULL)
850     return;
851
852   /* allocate float buffer outside of image buffer,
853    * so work-in-progress color space conversion doesn't
854    * interfere with other parts of blender
855    */
856   rect_float = ibuf->rect_float;
857   if (rect_float == NULL) {
858     size_t size;
859
860     size = ((size_t)ibuf->x) * ibuf->y;
861     size = size * 4 * sizeof(float);
862     ibuf->channels = 4;
863
864     rect_float = MEM_mapallocN(size, "IMB_float_from_rect");
865
866     if (rect_float == NULL)
867       return;
868   }
869
870   /* first, create float buffer in non-linear space */
871   IMB_buffer_float_from_byte(rect_float,
872                              (unsigned char *)ibuf->rect,
873                              IB_PROFILE_SRGB,
874                              IB_PROFILE_SRGB,
875                              false,
876                              ibuf->x,
877                              ibuf->y,
878                              ibuf->x,
879                              ibuf->x);
880
881   /* then make float be in linear space */
882   IMB_colormanagement_colorspace_to_scene_linear(
883       rect_float, ibuf->x, ibuf->y, ibuf->channels, ibuf->rect_colorspace, false);
884
885   /* byte buffer is straight alpha, float should always be premul */
886   IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y);
887
888   if (ibuf->rect_float == NULL) {
889     ibuf->rect_float = rect_float;
890     ibuf->mall |= IB_rectfloat;
891     ibuf->flags |= IB_rectfloat;
892   }
893 }
894
895 /**************************** Color to Grayscale *****************************/
896
897 /* no profile conversion */
898 void IMB_color_to_bw(ImBuf *ibuf)
899 {
900   float *rct_fl = ibuf->rect_float;
901   uchar *rct = (uchar *)ibuf->rect;
902   size_t i;
903
904   if (rct_fl) {
905     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4)
906       rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
907   }
908
909   if (rct) {
910     for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4)
911       rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
912   }
913 }
914
915 void IMB_buffer_float_clamp(float *buf, int width, int height)
916 {
917   size_t i, total = ((size_t)width) * height * 4;
918   for (i = 0; i < total; i++) {
919     buf[i] = min_ff(1.0, buf[i]);
920   }
921 }
922
923 void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
924 {
925   size_t total = ((size_t)width) * height;
926   float *fp = buf;
927   while (total--) {
928     premul_to_straight_v4(fp);
929     fp += 4;
930   }
931 }
932
933 void IMB_buffer_float_premultiply(float *buf, int width, int height)
934 {
935   size_t total = ((size_t)width) * height;
936   float *fp = buf;
937   while (total--) {
938     straight_to_premul_v4(fp);
939     fp += 4;
940   }
941 }
942
943 /**************************** alter saturation *****************************/
944
945 void IMB_saturation(ImBuf *ibuf, float sat)
946 {
947   size_t i;
948   unsigned char *rct = (unsigned char *)ibuf->rect;
949   float *rct_fl = ibuf->rect_float;
950   float hsv[3];
951
952   if (rct) {
953     float rgb[3];
954     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
955       rgb_uchar_to_float(rgb, rct);
956       rgb_to_hsv_v(rgb, hsv);
957       hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
958       rgb_float_to_uchar(rct, rgb);
959     }
960   }
961
962   if (rct_fl) {
963     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
964       rgb_to_hsv_v(rct_fl, hsv);
965       hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
966     }
967   }
968 }