Keymap: pressing leader key (Alt) again closes tool prompt
[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 /* Test if colorspace conversions of pixels in buffer need to take into account alpha. */
100 bool IMB_alpha_affects_rgb(const ImBuf *ibuf)
101 {
102   return (ibuf->flags & IB_alphamode_channel_packed) == 0;
103 }
104
105 /* float to byte pixels, output 4-channel RGBA */
106 void IMB_buffer_byte_from_float(uchar *rect_to,
107                                 const float *rect_from,
108                                 int channels_from,
109                                 float dither,
110                                 int profile_to,
111                                 int profile_from,
112                                 bool predivide,
113                                 int width,
114                                 int height,
115                                 int stride_to,
116                                 int stride_from)
117 {
118   float tmp[4];
119   int x, y;
120   DitherContext *di = NULL;
121   float inv_width = 1.0f / width;
122   float inv_height = 1.0f / height;
123
124   /* we need valid profiles */
125   BLI_assert(profile_to != IB_PROFILE_NONE);
126   BLI_assert(profile_from != IB_PROFILE_NONE);
127
128   if (dither) {
129     di = create_dither_context(dither);
130   }
131
132   for (y = 0; y < height; y++) {
133     float t = y * inv_height;
134
135     if (channels_from == 1) {
136       /* single channel input */
137       const float *from = rect_from + ((size_t)stride_from) * y;
138       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
139
140       for (x = 0; x < width; x++, from++, to += 4) {
141         to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
142       }
143     }
144     else if (channels_from == 3) {
145       /* RGB input */
146       const float *from = rect_from + ((size_t)stride_from) * y * 3;
147       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
148
149       if (profile_to == profile_from) {
150         /* no color space conversion */
151         for (x = 0; x < width; x++, from += 3, to += 4) {
152           rgb_float_to_uchar(to, from);
153           to[3] = 255;
154         }
155       }
156       else if (profile_to == IB_PROFILE_SRGB) {
157         /* convert from linear to sRGB */
158         for (x = 0; x < width; x++, from += 3, to += 4) {
159           linearrgb_to_srgb_v3_v3(tmp, from);
160           rgb_float_to_uchar(to, tmp);
161           to[3] = 255;
162         }
163       }
164       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
165         /* convert from sRGB to linear */
166         for (x = 0; x < width; x++, from += 3, to += 4) {
167           srgb_to_linearrgb_v3_v3(tmp, from);
168           rgb_float_to_uchar(to, tmp);
169           to[3] = 255;
170         }
171       }
172     }
173     else if (channels_from == 4) {
174       /* RGBA input */
175       const float *from = rect_from + ((size_t)stride_from) * y * 4;
176       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
177
178       if (profile_to == profile_from) {
179         float straight[4];
180
181         /* no color space conversion */
182         if (dither && predivide) {
183           for (x = 0; x < width; x++, from += 4, to += 4) {
184             premul_to_straight_v4_v4(straight, from);
185             float_to_byte_dither_v4(to, straight, di, (float)x * inv_width, t);
186           }
187         }
188         else if (dither) {
189           for (x = 0; x < width; x++, from += 4, to += 4) {
190             float_to_byte_dither_v4(to, from, di, (float)x * inv_width, t);
191           }
192         }
193         else if (predivide) {
194           for (x = 0; x < width; x++, from += 4, to += 4) {
195             premul_to_straight_v4_v4(straight, from);
196             rgba_float_to_uchar(to, straight);
197           }
198         }
199         else {
200           for (x = 0; x < width; x++, from += 4, to += 4) {
201             rgba_float_to_uchar(to, from);
202           }
203         }
204       }
205       else if (profile_to == IB_PROFILE_SRGB) {
206         /* convert from linear to sRGB */
207         unsigned short us[4];
208         float straight[4];
209
210         if (dither && predivide) {
211           for (x = 0; x < width; x++, from += 4, to += 4) {
212             premul_to_straight_v4_v4(straight, from);
213             linearrgb_to_srgb_ushort4(us, from);
214             ushort_to_byte_dither_v4(to, us, di, (float)x * inv_width, t);
215           }
216         }
217         else if (dither) {
218           for (x = 0; x < width; x++, from += 4, to += 4) {
219             linearrgb_to_srgb_ushort4(us, from);
220             ushort_to_byte_dither_v4(to, us, di, (float)x * inv_width, t);
221           }
222         }
223         else if (predivide) {
224           for (x = 0; x < width; x++, from += 4, to += 4) {
225             premul_to_straight_v4_v4(straight, from);
226             linearrgb_to_srgb_ushort4(us, from);
227             ushort_to_byte_v4(to, us);
228           }
229         }
230         else {
231           for (x = 0; x < width; x++, from += 4, to += 4) {
232             linearrgb_to_srgb_ushort4(us, from);
233             ushort_to_byte_v4(to, us);
234           }
235         }
236       }
237       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
238         /* convert from sRGB to linear */
239         if (dither && predivide) {
240           for (x = 0; x < width; x++, from += 4, to += 4) {
241             srgb_to_linearrgb_predivide_v4(tmp, from);
242             float_to_byte_dither_v4(to, tmp, di, (float)x * inv_width, t);
243           }
244         }
245         else if (dither) {
246           for (x = 0; x < width; x++, from += 4, to += 4) {
247             srgb_to_linearrgb_v4(tmp, from);
248             float_to_byte_dither_v4(to, tmp, di, (float)x * inv_width, t);
249           }
250         }
251         else if (predivide) {
252           for (x = 0; x < width; x++, from += 4, to += 4) {
253             srgb_to_linearrgb_predivide_v4(tmp, from);
254             rgba_float_to_uchar(to, tmp);
255           }
256         }
257         else {
258           for (x = 0; x < width; x++, from += 4, to += 4) {
259             srgb_to_linearrgb_v4(tmp, from);
260             rgba_float_to_uchar(to, tmp);
261           }
262         }
263       }
264     }
265   }
266
267   if (dither) {
268     clear_dither_context(di);
269   }
270 }
271
272 /* float to byte pixels, output 4-channel RGBA */
273 void IMB_buffer_byte_from_float_mask(uchar *rect_to,
274                                      const float *rect_from,
275                                      int channels_from,
276                                      float dither,
277                                      bool predivide,
278                                      int width,
279                                      int height,
280                                      int stride_to,
281                                      int stride_from,
282                                      char *mask)
283 {
284   int x, y;
285   DitherContext *di = NULL;
286   float inv_width = 1.0f / width, inv_height = 1.0f / height;
287
288   if (dither) {
289     di = create_dither_context(dither);
290   }
291
292   for (y = 0; y < height; y++) {
293     float t = y * inv_height;
294
295     if (channels_from == 1) {
296       /* single channel input */
297       const float *from = rect_from + ((size_t)stride_from) * y;
298       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
299
300       for (x = 0; x < width; x++, from++, to += 4) {
301         if (*mask++ == FILTER_MASK_USED) {
302           to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
303         }
304       }
305     }
306     else if (channels_from == 3) {
307       /* RGB input */
308       const float *from = rect_from + ((size_t)stride_from) * y * 3;
309       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
310
311       for (x = 0; x < width; x++, from += 3, to += 4) {
312         if (*mask++ == FILTER_MASK_USED) {
313           rgb_float_to_uchar(to, from);
314           to[3] = 255;
315         }
316       }
317     }
318     else if (channels_from == 4) {
319       /* RGBA input */
320       const float *from = rect_from + ((size_t)stride_from) * y * 4;
321       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
322
323       float straight[4];
324
325       if (dither && predivide) {
326         for (x = 0; x < width; x++, from += 4, to += 4) {
327           if (*mask++ == FILTER_MASK_USED) {
328             premul_to_straight_v4_v4(straight, from);
329             float_to_byte_dither_v4(to, straight, di, (float)x * inv_width, t);
330           }
331         }
332       }
333       else if (dither) {
334         for (x = 0; x < width; x++, from += 4, to += 4) {
335           if (*mask++ == FILTER_MASK_USED) {
336             float_to_byte_dither_v4(to, from, di, (float)x * inv_width, t);
337           }
338         }
339       }
340       else if (predivide) {
341         for (x = 0; x < width; x++, from += 4, to += 4) {
342           if (*mask++ == FILTER_MASK_USED) {
343             premul_to_straight_v4_v4(straight, from);
344             rgba_float_to_uchar(to, straight);
345           }
346         }
347       }
348       else {
349         for (x = 0; x < width; x++, from += 4, to += 4) {
350           if (*mask++ == FILTER_MASK_USED) {
351             rgba_float_to_uchar(to, from);
352           }
353         }
354       }
355     }
356   }
357
358   if (dither) {
359     clear_dither_context(di);
360   }
361 }
362
363 /* byte to float pixels, input and output 4-channel RGBA  */
364 void IMB_buffer_float_from_byte(float *rect_to,
365                                 const uchar *rect_from,
366                                 int profile_to,
367                                 int profile_from,
368                                 bool predivide,
369                                 int width,
370                                 int height,
371                                 int stride_to,
372                                 int stride_from)
373 {
374   float tmp[4];
375   int x, y;
376
377   /* we need valid profiles */
378   BLI_assert(profile_to != IB_PROFILE_NONE);
379   BLI_assert(profile_from != IB_PROFILE_NONE);
380
381   /* RGBA input */
382   for (y = 0; y < height; y++) {
383     const uchar *from = rect_from + stride_from * y * 4;
384     float *to = rect_to + ((size_t)stride_to) * y * 4;
385
386     if (profile_to == profile_from) {
387       /* no color space conversion */
388       for (x = 0; x < width; x++, from += 4, to += 4) {
389         rgba_uchar_to_float(to, from);
390       }
391     }
392     else if (profile_to == IB_PROFILE_LINEAR_RGB) {
393       /* convert sRGB to linear */
394       if (predivide) {
395         for (x = 0; x < width; x++, from += 4, to += 4) {
396           srgb_to_linearrgb_uchar4_predivide(to, from);
397         }
398       }
399       else {
400         for (x = 0; x < width; x++, from += 4, to += 4) {
401           srgb_to_linearrgb_uchar4(to, from);
402         }
403       }
404     }
405     else if (profile_to == IB_PROFILE_SRGB) {
406       /* convert linear to sRGB */
407       if (predivide) {
408         for (x = 0; x < width; x++, from += 4, to += 4) {
409           rgba_uchar_to_float(tmp, from);
410           linearrgb_to_srgb_predivide_v4(to, tmp);
411         }
412       }
413       else {
414         for (x = 0; x < width; x++, from += 4, to += 4) {
415           rgba_uchar_to_float(tmp, from);
416           linearrgb_to_srgb_v4(to, tmp);
417         }
418       }
419     }
420   }
421 }
422
423 /* float to float pixels, output 4-channel RGBA */
424 void IMB_buffer_float_from_float(float *rect_to,
425                                  const float *rect_from,
426                                  int channels_from,
427                                  int profile_to,
428                                  int profile_from,
429                                  bool predivide,
430                                  int width,
431                                  int height,
432                                  int stride_to,
433                                  int stride_from)
434 {
435   int x, y;
436
437   /* we need valid profiles */
438   BLI_assert(profile_to != IB_PROFILE_NONE);
439   BLI_assert(profile_from != IB_PROFILE_NONE);
440
441   if (channels_from == 1) {
442     /* single channel input */
443     for (y = 0; y < height; y++) {
444       const float *from = rect_from + ((size_t)stride_from) * y;
445       float *to = rect_to + ((size_t)stride_to) * y * 4;
446
447       for (x = 0; x < width; x++, from++, to += 4) {
448         to[0] = to[1] = to[2] = to[3] = from[0];
449       }
450     }
451   }
452   else if (channels_from == 3) {
453     /* RGB input */
454     for (y = 0; y < height; y++) {
455       const float *from = rect_from + ((size_t)stride_from) * y * 3;
456       float *to = rect_to + ((size_t)stride_to) * y * 4;
457
458       if (profile_to == profile_from) {
459         /* no color space conversion */
460         for (x = 0; x < width; x++, from += 3, to += 4) {
461           copy_v3_v3(to, from);
462           to[3] = 1.0f;
463         }
464       }
465       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
466         /* convert from sRGB to linear */
467         for (x = 0; x < width; x++, from += 3, to += 4) {
468           srgb_to_linearrgb_v3_v3(to, from);
469           to[3] = 1.0f;
470         }
471       }
472       else if (profile_to == IB_PROFILE_SRGB) {
473         /* convert from linear to sRGB */
474         for (x = 0; x < width; x++, from += 3, to += 4) {
475           linearrgb_to_srgb_v3_v3(to, from);
476           to[3] = 1.0f;
477         }
478       }
479     }
480   }
481   else if (channels_from == 4) {
482     /* RGBA input */
483     for (y = 0; y < height; y++) {
484       const float *from = rect_from + ((size_t)stride_from) * y * 4;
485       float *to = rect_to + ((size_t)stride_to) * y * 4;
486
487       if (profile_to == profile_from) {
488         /* same profile, copy */
489         memcpy(to, from, sizeof(float) * ((size_t)4) * width);
490       }
491       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
492         /* convert to sRGB to linear */
493         if (predivide) {
494           for (x = 0; x < width; x++, from += 4, to += 4) {
495             srgb_to_linearrgb_predivide_v4(to, from);
496           }
497         }
498         else {
499           for (x = 0; x < width; x++, from += 4, to += 4) {
500             srgb_to_linearrgb_v4(to, from);
501           }
502         }
503       }
504       else if (profile_to == IB_PROFILE_SRGB) {
505         /* convert from linear to sRGB */
506         if (predivide) {
507           for (x = 0; x < width; x++, from += 4, to += 4) {
508             linearrgb_to_srgb_predivide_v4(to, from);
509           }
510         }
511         else {
512           for (x = 0; x < width; x++, from += 4, to += 4) {
513             linearrgb_to_srgb_v4(to, from);
514           }
515         }
516       }
517     }
518   }
519 }
520
521 typedef struct FloatToFloatThreadData {
522   float *rect_to;
523   const float *rect_from;
524   int channels_from;
525   int profile_to;
526   int profile_from;
527   bool predivide;
528   int width;
529   int stride_to;
530   int stride_from;
531 } FloatToFloatThreadData;
532
533 static void imb_buffer_float_from_float_thread_do(void *data_v,
534                                                   int start_scanline,
535                                                   int num_scanlines)
536 {
537   FloatToFloatThreadData *data = (FloatToFloatThreadData *)data_v;
538   size_t offset_from = ((size_t)start_scanline) * data->stride_from * data->channels_from;
539   size_t offset_to = ((size_t)start_scanline) * data->stride_to * data->channels_from;
540   IMB_buffer_float_from_float(data->rect_to + offset_to,
541                               data->rect_from + offset_from,
542                               data->channels_from,
543                               data->profile_to,
544                               data->profile_from,
545                               data->predivide,
546                               data->width,
547                               num_scanlines,
548                               data->stride_to,
549                               data->stride_from);
550 }
551
552 void IMB_buffer_float_from_float_threaded(float *rect_to,
553                                           const float *rect_from,
554                                           int channels_from,
555                                           int profile_to,
556                                           int profile_from,
557                                           bool predivide,
558                                           int width,
559                                           int height,
560                                           int stride_to,
561                                           int stride_from)
562 {
563   if (((size_t)width) * height < 64 * 64) {
564     IMB_buffer_float_from_float(rect_to,
565                                 rect_from,
566                                 channels_from,
567                                 profile_to,
568                                 profile_from,
569                                 predivide,
570                                 width,
571                                 height,
572                                 stride_to,
573                                 stride_from);
574   }
575   else {
576     FloatToFloatThreadData data;
577     data.rect_to = rect_to;
578     data.rect_from = rect_from;
579     data.channels_from = channels_from;
580     data.profile_to = profile_to;
581     data.profile_from = profile_from;
582     data.predivide = predivide;
583     data.width = width;
584     data.stride_to = stride_to;
585     data.stride_from = stride_from;
586     IMB_processor_apply_threaded_scanlines(height, imb_buffer_float_from_float_thread_do, &data);
587   }
588 }
589
590 /* float to float pixels, output 4-channel RGBA */
591 void IMB_buffer_float_from_float_mask(float *rect_to,
592                                       const float *rect_from,
593                                       int channels_from,
594                                       int width,
595                                       int height,
596                                       int stride_to,
597                                       int stride_from,
598                                       char *mask)
599 {
600   int x, y;
601
602   if (channels_from == 1) {
603     /* single channel input */
604     for (y = 0; y < height; y++) {
605       const float *from = rect_from + ((size_t)stride_from) * y;
606       float *to = rect_to + ((size_t)stride_to) * y * 4;
607
608       for (x = 0; x < width; x++, from++, to += 4) {
609         if (*mask++ == FILTER_MASK_USED) {
610           to[0] = to[1] = to[2] = to[3] = from[0];
611         }
612       }
613     }
614   }
615   else if (channels_from == 3) {
616     /* RGB input */
617     for (y = 0; y < height; y++) {
618       const float *from = rect_from + ((size_t)stride_from) * y * 3;
619       float *to = rect_to + ((size_t)stride_to) * y * 4;
620
621       for (x = 0; x < width; x++, from += 3, to += 4) {
622         if (*mask++ == FILTER_MASK_USED) {
623           copy_v3_v3(to, from);
624           to[3] = 1.0f;
625         }
626       }
627     }
628   }
629   else if (channels_from == 4) {
630     /* RGBA input */
631     for (y = 0; y < height; y++) {
632       const float *from = rect_from + ((size_t)stride_from) * y * 4;
633       float *to = rect_to + ((size_t)stride_to) * y * 4;
634
635       for (x = 0; x < width; x++, from += 4, to += 4) {
636         if (*mask++ == FILTER_MASK_USED) {
637           copy_v4_v4(to, from);
638         }
639       }
640     }
641   }
642 }
643
644 /* byte to byte pixels, input and output 4-channel RGBA */
645 void IMB_buffer_byte_from_byte(uchar *rect_to,
646                                const uchar *rect_from,
647                                int profile_to,
648                                int profile_from,
649                                bool predivide,
650                                int width,
651                                int height,
652                                int stride_to,
653                                int stride_from)
654 {
655   float tmp[4];
656   int x, y;
657
658   /* we need valid profiles */
659   BLI_assert(profile_to != IB_PROFILE_NONE);
660   BLI_assert(profile_from != IB_PROFILE_NONE);
661
662   /* always RGBA input */
663   for (y = 0; y < height; y++) {
664     const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
665     uchar *to = rect_to + ((size_t)stride_to) * y * 4;
666
667     if (profile_to == profile_from) {
668       /* same profile, copy */
669       memcpy(to, from, sizeof(uchar) * 4 * width);
670     }
671     else if (profile_to == IB_PROFILE_LINEAR_RGB) {
672       /* convert to sRGB to linear */
673       if (predivide) {
674         for (x = 0; x < width; x++, from += 4, to += 4) {
675           rgba_uchar_to_float(tmp, from);
676           srgb_to_linearrgb_predivide_v4(tmp, tmp);
677           rgba_float_to_uchar(to, tmp);
678         }
679       }
680       else {
681         for (x = 0; x < width; x++, from += 4, to += 4) {
682           rgba_uchar_to_float(tmp, from);
683           srgb_to_linearrgb_v4(tmp, tmp);
684           rgba_float_to_uchar(to, tmp);
685         }
686       }
687     }
688     else if (profile_to == IB_PROFILE_SRGB) {
689       /* convert from linear to sRGB */
690       if (predivide) {
691         for (x = 0; x < width; x++, from += 4, to += 4) {
692           rgba_uchar_to_float(tmp, from);
693           linearrgb_to_srgb_predivide_v4(tmp, tmp);
694           rgba_float_to_uchar(to, tmp);
695         }
696       }
697       else {
698         for (x = 0; x < width; x++, from += 4, to += 4) {
699           rgba_uchar_to_float(tmp, from);
700           linearrgb_to_srgb_v4(tmp, tmp);
701           rgba_float_to_uchar(to, tmp);
702         }
703       }
704     }
705   }
706 }
707
708 /****************************** ImBuf Conversion *****************************/
709
710 void IMB_rect_from_float(ImBuf *ibuf)
711 {
712   float *buffer;
713   const char *from_colorspace;
714
715   /* verify we have a float buffer */
716   if (ibuf->rect_float == NULL) {
717     return;
718   }
719
720   /* create byte rect if it didn't exist yet */
721   if (ibuf->rect == NULL) {
722     if (imb_addrectImBuf(ibuf) == 0) {
723       return;
724     }
725   }
726
727   if (ibuf->float_colorspace == NULL) {
728     from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
729   }
730   else {
731     from_colorspace = ibuf->float_colorspace->name;
732   }
733
734   buffer = MEM_dupallocN(ibuf->rect_float);
735
736   /* first make float buffer in byte space */
737   const bool predivide = IMB_alpha_affects_rgb(ibuf);
738   IMB_colormanagement_transform(buffer,
739                                 ibuf->x,
740                                 ibuf->y,
741                                 ibuf->channels,
742                                 from_colorspace,
743                                 ibuf->rect_colorspace->name,
744                                 predivide);
745
746   /* convert from float's premul alpha to byte's straight alpha */
747   if (IMB_alpha_affects_rgb(ibuf)) {
748     IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y);
749   }
750
751   /* convert float to byte */
752   IMB_buffer_byte_from_float((unsigned char *)ibuf->rect,
753                              buffer,
754                              ibuf->channels,
755                              ibuf->dither,
756                              IB_PROFILE_SRGB,
757                              IB_PROFILE_SRGB,
758                              false,
759                              ibuf->x,
760                              ibuf->y,
761                              ibuf->x,
762                              ibuf->x);
763
764   MEM_freeN(buffer);
765
766   /* ensure user flag is reset */
767   ibuf->userflags &= ~IB_RECT_INVALID;
768 }
769
770 void IMB_float_from_rect(ImBuf *ibuf)
771 {
772   float *rect_float;
773
774   /* verify if we byte and float buffers */
775   if (ibuf->rect == NULL) {
776     return;
777   }
778
779   /* allocate float buffer outside of image buffer,
780    * so work-in-progress color space conversion doesn't
781    * interfere with other parts of blender
782    */
783   rect_float = ibuf->rect_float;
784   if (rect_float == NULL) {
785     size_t size;
786
787     size = ((size_t)ibuf->x) * ibuf->y;
788     size = size * 4 * sizeof(float);
789     ibuf->channels = 4;
790
791     rect_float = MEM_mapallocN(size, "IMB_float_from_rect");
792
793     if (rect_float == NULL) {
794       return;
795     }
796   }
797
798   /* first, create float buffer in non-linear space */
799   IMB_buffer_float_from_byte(rect_float,
800                              (unsigned char *)ibuf->rect,
801                              IB_PROFILE_SRGB,
802                              IB_PROFILE_SRGB,
803                              false,
804                              ibuf->x,
805                              ibuf->y,
806                              ibuf->x,
807                              ibuf->x);
808
809   /* then make float be in linear space */
810   IMB_colormanagement_colorspace_to_scene_linear(
811       rect_float, ibuf->x, ibuf->y, ibuf->channels, ibuf->rect_colorspace, false);
812
813   /* byte buffer is straight alpha, float should always be premul */
814   if (IMB_alpha_affects_rgb(ibuf)) {
815     IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y);
816   }
817
818   if (ibuf->rect_float == NULL) {
819     ibuf->rect_float = rect_float;
820     ibuf->mall |= IB_rectfloat;
821     ibuf->flags |= IB_rectfloat;
822   }
823 }
824
825 /**************************** Color to Grayscale *****************************/
826
827 /* no profile conversion */
828 void IMB_color_to_bw(ImBuf *ibuf)
829 {
830   float *rct_fl = ibuf->rect_float;
831   uchar *rct = (uchar *)ibuf->rect;
832   size_t i;
833
834   if (rct_fl) {
835     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
836       rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
837     }
838   }
839
840   if (rct) {
841     for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4) {
842       rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
843     }
844   }
845 }
846
847 void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
848 {
849   size_t total = ((size_t)width) * height;
850   float *fp = buf;
851   while (total--) {
852     premul_to_straight_v4(fp);
853     fp += 4;
854   }
855 }
856
857 void IMB_buffer_float_premultiply(float *buf, int width, int height)
858 {
859   size_t total = ((size_t)width) * height;
860   float *fp = buf;
861   while (total--) {
862     straight_to_premul_v4(fp);
863     fp += 4;
864   }
865 }
866
867 /**************************** alter saturation *****************************/
868
869 void IMB_saturation(ImBuf *ibuf, float sat)
870 {
871   size_t i;
872   unsigned char *rct = (unsigned char *)ibuf->rect;
873   float *rct_fl = ibuf->rect_float;
874   float hsv[3];
875
876   if (rct) {
877     float rgb[3];
878     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
879       rgb_uchar_to_float(rgb, rct);
880       rgb_to_hsv_v(rgb, hsv);
881       hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
882       rgb_float_to_uchar(rct, rgb);
883     }
884   }
885
886   if (rct_fl) {
887     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
888       rgb_to_hsv_v(rct_fl, hsv);
889       hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
890     }
891   }
892 }