Blender V4.5
conversion.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 * SPDX-FileCopyrightText: 2024 Blender Authors
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later */
5
9
10#include "BLI_rect.h"
11#include "BLI_task.hh"
12
13#include "IMB_filter.hh"
14#include "IMB_imbuf.hh"
15#include "IMB_imbuf_types.hh"
16
19
20#include "MEM_guardedalloc.h"
21
22#include "OCIO_colorspace.hh"
23
24/* -------------------------------------------------------------------- */
25
28
29MINLINE void ushort_to_byte_v4(uchar b[4], const ushort us[4])
30{
31 b[0] = unit_ushort_to_uchar(us[0]);
32 b[1] = unit_ushort_to_uchar(us[1]);
33 b[2] = unit_ushort_to_uchar(us[2]);
34 b[3] = unit_ushort_to_uchar(us[3]);
35}
36
37MINLINE uchar ftochar(float value)
38{
39 return unit_float_to_uchar_clamp(value);
40}
41
42MINLINE void ushort_to_byte_dither_v4(uchar b[4], const ushort us[4], float dither, int x, int y)
43{
44#define USHORTTOFLOAT(val) (float(val) / 65535.0f)
45 float dither_value = dither_random_value(x, y) * 0.0033f * dither;
46
47 b[0] = ftochar(dither_value + USHORTTOFLOAT(us[0]));
48 b[1] = ftochar(dither_value + USHORTTOFLOAT(us[1]));
49 b[2] = ftochar(dither_value + USHORTTOFLOAT(us[2]));
50 b[3] = unit_ushort_to_uchar(us[3]);
51
52#undef USHORTTOFLOAT
53}
54
55MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], float dither, int x, int y)
56{
57 float dither_value = dither_random_value(x, y) * 0.0033f * dither;
58
59 b[0] = ftochar(dither_value + f[0]);
60 b[1] = ftochar(dither_value + f[1]);
61 b[2] = ftochar(dither_value + f[2]);
63}
64
66{
67 return ibuf && (ibuf->flags & IB_alphamode_channel_packed) == 0;
68}
69
71 const float *rect_from,
72 int channels_from,
73 float dither,
74 int profile_to,
75 int profile_from,
76 bool predivide,
77 int width,
78 int height,
79 int stride_to,
80 int stride_from,
81 int start_y)
82{
83 float tmp[4];
84 int x, y;
85
86 /* we need valid profiles */
87 BLI_assert(profile_to != IB_PROFILE_NONE);
88 BLI_assert(profile_from != IB_PROFILE_NONE);
89
90 for (y = 0; y < height; y++) {
91 if (channels_from == 1) {
92 /* single channel input */
93 const float *from = rect_from + size_t(stride_from) * y;
94 uchar *to = rect_to + size_t(stride_to) * y * 4;
95
96 for (x = 0; x < width; x++, from++, to += 4) {
97 to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
98 }
99 }
100 else if (channels_from == 3) {
101 /* RGB input */
102 const float *from = rect_from + size_t(stride_from) * y * 3;
103 uchar *to = rect_to + size_t(stride_to) * y * 4;
104
105 if (profile_to == profile_from) {
106 /* no color space conversion */
107 for (x = 0; x < width; x++, from += 3, to += 4) {
108 rgb_float_to_uchar(to, from);
109 to[3] = 255;
110 }
111 }
112 else if (profile_to == IB_PROFILE_SRGB) {
113 /* convert from linear to sRGB */
114 for (x = 0; x < width; x++, from += 3, to += 4) {
115 linearrgb_to_srgb_v3_v3(tmp, from);
116 rgb_float_to_uchar(to, tmp);
117 to[3] = 255;
118 }
119 }
120 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
121 /* convert from sRGB to linear */
122 for (x = 0; x < width; x++, from += 3, to += 4) {
123 srgb_to_linearrgb_v3_v3(tmp, from);
124 rgb_float_to_uchar(to, tmp);
125 to[3] = 255;
126 }
127 }
128 }
129 else if (channels_from == 4) {
130 /* RGBA input */
131 const float *from = rect_from + size_t(stride_from) * y * 4;
132 uchar *to = rect_to + size_t(stride_to) * y * 4;
133
134 if (profile_to == profile_from) {
135 /* no color space conversion */
136 if (dither && predivide) {
137 float straight[4];
138 for (x = 0; x < width; x++, from += 4, to += 4) {
139 premul_to_straight_v4_v4(straight, from);
140 float_to_byte_dither_v4(to, straight, dither, x, y + start_y);
141 }
142 }
143 else if (dither) {
144 for (x = 0; x < width; x++, from += 4, to += 4) {
145 float_to_byte_dither_v4(to, from, dither, x, y + start_y);
146 }
147 }
148 else if (predivide) {
149 for (x = 0; x < width; x++, from += 4, to += 4) {
151 }
152 }
153 else {
154 for (x = 0; x < width; x++, from += 4, to += 4) {
155 rgba_float_to_uchar(to, from);
156 }
157 }
158 }
159 else if (profile_to == IB_PROFILE_SRGB) {
160 /* convert from linear to sRGB */
161 ushort us[4];
162 float straight[4];
163
164 if (dither && predivide) {
165 for (x = 0; x < width; x++, from += 4, to += 4) {
166 premul_to_straight_v4_v4(straight, from);
168 ushort_to_byte_dither_v4(to, us, dither, x, y + start_y);
169 }
170 }
171 else if (dither) {
172 for (x = 0; x < width; x++, from += 4, to += 4) {
174 ushort_to_byte_dither_v4(to, us, dither, x, y + start_y);
175 }
176 }
177 else if (predivide) {
178 for (x = 0; x < width; x++, from += 4, to += 4) {
179 premul_to_straight_v4_v4(straight, from);
181 ushort_to_byte_v4(to, us);
182 }
183 }
184 else {
185 for (x = 0; x < width; x++, from += 4, to += 4) {
187 ushort_to_byte_v4(to, us);
188 }
189 }
190 }
191 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
192 /* convert from sRGB to linear */
193 if (dither && predivide) {
194 for (x = 0; x < width; x++, from += 4, to += 4) {
196 float_to_byte_dither_v4(to, tmp, dither, x, y + start_y);
197 }
198 }
199 else if (dither) {
200 for (x = 0; x < width; x++, from += 4, to += 4) {
201 srgb_to_linearrgb_v4(tmp, from);
202 float_to_byte_dither_v4(to, tmp, dither, x, y + start_y);
203 }
204 }
205 else if (predivide) {
206 for (x = 0; x < width; x++, from += 4, to += 4) {
208 rgba_float_to_uchar(to, tmp);
209 }
210 }
211 else {
212 for (x = 0; x < width; x++, from += 4, to += 4) {
213 srgb_to_linearrgb_v4(tmp, from);
214 rgba_float_to_uchar(to, tmp);
215 }
216 }
217 }
218 }
219 }
220}
221
223 const float *rect_from,
224 int channels_from,
225 float dither,
226 bool predivide,
227 int width,
228 int height,
229 int stride_to,
230 int stride_from,
231 char *mask)
232{
233 int x, y;
234
235 for (y = 0; y < height; y++) {
236 if (channels_from == 1) {
237 /* single channel input */
238 const float *from = rect_from + size_t(stride_from) * y;
239 uchar *to = rect_to + size_t(stride_to) * y * 4;
240
241 for (x = 0; x < width; x++, from++, to += 4) {
242 if (*mask++ == FILTER_MASK_USED) {
243 to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
244 }
245 }
246 }
247 else if (channels_from == 3) {
248 /* RGB input */
249 const float *from = rect_from + size_t(stride_from) * y * 3;
250 uchar *to = rect_to + size_t(stride_to) * y * 4;
251
252 for (x = 0; x < width; x++, from += 3, to += 4) {
253 if (*mask++ == FILTER_MASK_USED) {
254 rgb_float_to_uchar(to, from);
255 to[3] = 255;
256 }
257 }
258 }
259 else if (channels_from == 4) {
260 /* RGBA input */
261 const float *from = rect_from + size_t(stride_from) * y * 4;
262 uchar *to = rect_to + size_t(stride_to) * y * 4;
263
264 if (dither && predivide) {
265 float straight[4];
266 for (x = 0; x < width; x++, from += 4, to += 4) {
267 if (*mask++ == FILTER_MASK_USED) {
268 premul_to_straight_v4_v4(straight, from);
269 float_to_byte_dither_v4(to, straight, dither, x, y);
270 }
271 }
272 }
273 else if (dither) {
274 for (x = 0; x < width; x++, from += 4, to += 4) {
275 if (*mask++ == FILTER_MASK_USED) {
276 float_to_byte_dither_v4(to, from, dither, x, y);
277 }
278 }
279 }
280 else if (predivide) {
281 for (x = 0; x < width; x++, from += 4, to += 4) {
282 if (*mask++ == FILTER_MASK_USED) {
284 }
285 }
286 }
287 else {
288 for (x = 0; x < width; x++, from += 4, to += 4) {
289 if (*mask++ == FILTER_MASK_USED) {
290 rgba_float_to_uchar(to, from);
291 }
292 }
293 }
294 }
295 }
296}
297
298void IMB_buffer_float_from_byte(float *rect_to,
299 const uchar *rect_from,
300 int profile_to,
301 int profile_from,
302 bool predivide,
303 int width,
304 int height,
305 int stride_to,
306 int stride_from)
307{
308 float tmp[4];
309 int x, y;
310
311 /* we need valid profiles */
312 BLI_assert(profile_to != IB_PROFILE_NONE);
313 BLI_assert(profile_from != IB_PROFILE_NONE);
314
315 /* RGBA input */
316 for (y = 0; y < height; y++) {
317 const uchar *from = rect_from + size_t(stride_from) * y * 4;
318 float *to = rect_to + size_t(stride_to) * y * 4;
319
320 if (profile_to == profile_from) {
321 /* no color space conversion */
322 for (x = 0; x < width; x++, from += 4, to += 4) {
323 rgba_uchar_to_float(to, from);
324 }
325 }
326 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
327 /* convert sRGB to linear */
328 if (predivide) {
329 for (x = 0; x < width; x++, from += 4, to += 4) {
331 }
332 }
333 else {
334 for (x = 0; x < width; x++, from += 4, to += 4) {
335 srgb_to_linearrgb_uchar4(to, from);
336 }
337 }
338 }
339 else if (profile_to == IB_PROFILE_SRGB) {
340 /* convert linear to sRGB */
341 if (predivide) {
342 for (x = 0; x < width; x++, from += 4, to += 4) {
343 rgba_uchar_to_float(tmp, from);
345 }
346 }
347 else {
348 for (x = 0; x < width; x++, from += 4, to += 4) {
349 rgba_uchar_to_float(tmp, from);
350 linearrgb_to_srgb_v4(to, tmp);
351 }
352 }
353 }
354 }
355}
356
357void IMB_buffer_float_from_float(float *rect_to,
358 const float *rect_from,
359 int channels_from,
360 int profile_to,
361 int profile_from,
362 bool predivide,
363 int width,
364 int height,
365 int stride_to,
366 int stride_from)
367{
368 int x, y;
369
370 /* we need valid profiles */
371 BLI_assert(profile_to != IB_PROFILE_NONE);
372 BLI_assert(profile_from != IB_PROFILE_NONE);
373
374 if (channels_from == 1) {
375 /* single channel input */
376 for (y = 0; y < height; y++) {
377 const float *from = rect_from + size_t(stride_from) * y;
378 float *to = rect_to + size_t(stride_to) * y * 4;
379
380 for (x = 0; x < width; x++, from++, to += 4) {
381 to[0] = to[1] = to[2] = to[3] = from[0];
382 }
383 }
384 }
385 else if (channels_from == 3) {
386 /* RGB input */
387 for (y = 0; y < height; y++) {
388 const float *from = rect_from + size_t(stride_from) * y * 3;
389 float *to = rect_to + size_t(stride_to) * y * 4;
390
391 if (profile_to == profile_from) {
392 /* no color space conversion */
393 for (x = 0; x < width; x++, from += 3, to += 4) {
394 copy_v3_v3(to, from);
395 to[3] = 1.0f;
396 }
397 }
398 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
399 /* convert from sRGB to linear */
400 for (x = 0; x < width; x++, from += 3, to += 4) {
401 srgb_to_linearrgb_v3_v3(to, from);
402 to[3] = 1.0f;
403 }
404 }
405 else if (profile_to == IB_PROFILE_SRGB) {
406 /* convert from linear to sRGB */
407 for (x = 0; x < width; x++, from += 3, to += 4) {
408 linearrgb_to_srgb_v3_v3(to, from);
409 to[3] = 1.0f;
410 }
411 }
412 }
413 }
414 else if (channels_from == 4) {
415 /* RGBA input */
416 for (y = 0; y < height; y++) {
417 const float *from = rect_from + size_t(stride_from) * y * 4;
418 float *to = rect_to + size_t(stride_to) * y * 4;
419
420 if (profile_to == profile_from) {
421 /* same profile, copy */
422 memcpy(to, from, sizeof(float) * size_t(4) * width);
423 }
424 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
425 /* convert to sRGB to linear */
426 if (predivide) {
427 for (x = 0; x < width; x++, from += 4, to += 4) {
429 }
430 }
431 else {
432 for (x = 0; x < width; x++, from += 4, to += 4) {
433 srgb_to_linearrgb_v4(to, from);
434 }
435 }
436 }
437 else if (profile_to == IB_PROFILE_SRGB) {
438 /* convert from linear to sRGB */
439 if (predivide) {
440 for (x = 0; x < width; x++, from += 4, to += 4) {
442 }
443 }
444 else {
445 for (x = 0; x < width; x++, from += 4, to += 4) {
446 linearrgb_to_srgb_v4(to, from);
447 }
448 }
449 }
450 }
451 }
452}
453
455 const float *rect_from,
456 int channels_from,
457 int profile_to,
458 int profile_from,
459 bool predivide,
460 int width,
461 int height,
462 int stride_to,
463 int stride_from)
464{
465 using namespace blender;
466 threading::parallel_for(IndexRange(height), 64, [&](const IndexRange y_range) {
467 int64_t offset_from = y_range.first() * stride_from * channels_from;
468 int64_t offset_to = y_range.first() * stride_to * 4;
469 IMB_buffer_float_from_float(rect_to + offset_to,
470 rect_from + offset_from,
471 channels_from,
472 profile_to,
473 profile_from,
474 predivide,
475 width,
476 y_range.size(),
477 stride_to,
478 stride_from);
479 });
480}
481
483 const float *rect_from,
484 int channels_from,
485 int width,
486 int height,
487 int stride_to,
488 int stride_from,
489 char *mask)
490{
491 int x, y;
492
493 if (channels_from == 1) {
494 /* single channel input */
495 for (y = 0; y < height; y++) {
496 const float *from = rect_from + size_t(stride_from) * y;
497 float *to = rect_to + size_t(stride_to) * y * 4;
498
499 for (x = 0; x < width; x++, from++, to += 4) {
500 if (*mask++ == FILTER_MASK_USED) {
501 to[0] = to[1] = to[2] = to[3] = from[0];
502 }
503 }
504 }
505 }
506 else if (channels_from == 3) {
507 /* RGB input */
508 for (y = 0; y < height; y++) {
509 const float *from = rect_from + size_t(stride_from) * y * 3;
510 float *to = rect_to + size_t(stride_to) * y * 4;
511
512 for (x = 0; x < width; x++, from += 3, to += 4) {
513 if (*mask++ == FILTER_MASK_USED) {
514 copy_v3_v3(to, from);
515 to[3] = 1.0f;
516 }
517 }
518 }
519 }
520 else if (channels_from == 4) {
521 /* RGBA input */
522 for (y = 0; y < height; y++) {
523 const float *from = rect_from + size_t(stride_from) * y * 4;
524 float *to = rect_to + size_t(stride_to) * y * 4;
525
526 for (x = 0; x < width; x++, from += 4, to += 4) {
527 if (*mask++ == FILTER_MASK_USED) {
528 copy_v4_v4(to, from);
529 }
530 }
531 }
532 }
533}
534
536 const uchar *rect_from,
537 int profile_to,
538 int profile_from,
539 bool predivide,
540 int width,
541 int height,
542 int stride_to,
543 int stride_from)
544{
545 float tmp[4];
546 int x, y;
547
548 /* we need valid profiles */
549 BLI_assert(profile_to != IB_PROFILE_NONE);
550 BLI_assert(profile_from != IB_PROFILE_NONE);
551
552 /* always RGBA input */
553 for (y = 0; y < height; y++) {
554 const uchar *from = rect_from + size_t(stride_from) * y * 4;
555 uchar *to = rect_to + size_t(stride_to) * y * 4;
556
557 if (profile_to == profile_from) {
558 /* same profile, copy */
559 memcpy(to, from, sizeof(uchar[4]) * width);
560 }
561 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
562 /* convert to sRGB to linear */
563 if (predivide) {
564 for (x = 0; x < width; x++, from += 4, to += 4) {
565 rgba_uchar_to_float(tmp, from);
567 rgba_float_to_uchar(to, tmp);
568 }
569 }
570 else {
571 for (x = 0; x < width; x++, from += 4, to += 4) {
572 rgba_uchar_to_float(tmp, from);
573 srgb_to_linearrgb_v4(tmp, tmp);
574 rgba_float_to_uchar(to, tmp);
575 }
576 }
577 }
578 else if (profile_to == IB_PROFILE_SRGB) {
579 /* convert from linear to sRGB */
580 if (predivide) {
581 for (x = 0; x < width; x++, from += 4, to += 4) {
582 rgba_uchar_to_float(tmp, from);
584 rgba_float_to_uchar(to, tmp);
585 }
586 }
587 else {
588 for (x = 0; x < width; x++, from += 4, to += 4) {
589 rgba_uchar_to_float(tmp, from);
590 linearrgb_to_srgb_v4(tmp, tmp);
591 rgba_float_to_uchar(to, tmp);
592 }
593 }
594 }
595 }
596}
597
599
600/* -------------------------------------------------------------------- */
603
605{
606 /* verify we have a float buffer */
607 if (ibuf->float_buffer.data == nullptr) {
608 return;
609 }
610
611 /* create byte rect if it didn't exist yet */
612 if (ibuf->byte_buffer.data == nullptr) {
613 if (IMB_alloc_byte_pixels(ibuf, false) == 0) {
614 return;
615 }
616 }
617
618 const char *from_colorspace = (ibuf->float_buffer.colorspace == nullptr) ?
622 const char *to_colorspace = (ibuf->byte_buffer.colorspace == nullptr) ?
625 ibuf->byte_buffer.colorspace->name().c_str();
626
627 float *buffer = static_cast<float *>(MEM_dupallocN(ibuf->float_buffer.data));
628
629 /* first make float buffer in byte space */
630 const bool predivide = IMB_alpha_affects_rgb(ibuf);
632 buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, predivide);
633
634 /* convert from float's premul alpha to byte's straight alpha */
635 if (IMB_alpha_affects_rgb(ibuf)) {
636 IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y);
637 }
638
639 /* convert float to byte */
641 buffer,
642 ibuf->channels,
643 ibuf->dither,
646 false,
647 ibuf->x,
648 ibuf->y,
649 ibuf->x,
650 ibuf->x);
651
652 MEM_freeN(buffer);
653
654 /* ensure user flag is reset */
656}
657
658void IMB_float_from_byte_ex(ImBuf *dst, const ImBuf *src, const rcti *region_to_update)
659{
660 BLI_assert_msg(dst->float_buffer.data != nullptr,
661 "Destination buffer should have a float buffer assigned.");
662 BLI_assert_msg(src->byte_buffer.data != nullptr,
663 "Source buffer should have a byte buffer assigned.");
664 BLI_assert_msg(dst->x == src->x, "Source and destination buffer should have the same dimension");
665 BLI_assert_msg(dst->y == src->y, "Source and destination buffer should have the same dimension");
666 BLI_assert_msg(dst->channels = 4, "Destination buffer should have 4 channels.");
667 BLI_assert_msg(region_to_update->xmin >= 0,
668 "Region to update should be clipped to the given buffers.");
669 BLI_assert_msg(region_to_update->ymin >= 0,
670 "Region to update should be clipped to the given buffers.");
671 BLI_assert_msg(region_to_update->xmax <= dst->x,
672 "Region to update should be clipped to the given buffers.");
673 BLI_assert_msg(region_to_update->ymax <= dst->y,
674 "Region to update should be clipped to the given buffers.");
675
676 float *rect_float = dst->float_buffer.data;
677 rect_float += (region_to_update->xmin + region_to_update->ymin * dst->x) * 4;
678 uchar *rect = src->byte_buffer.data;
679 rect += (region_to_update->xmin + region_to_update->ymin * dst->x) * 4;
680 const int region_width = BLI_rcti_size_x(region_to_update);
681 const int region_height = BLI_rcti_size_y(region_to_update);
682
683 /* Convert byte buffer to float buffer without color or alpha conversion. */
685 rect,
688 false,
689 region_width,
690 region_height,
691 src->x,
692 dst->x);
693
694 /* Perform color space conversion from rect color space to linear. */
695 float *float_ptr = rect_float;
696 for (int i = 0; i < region_height; i++) {
698 float_ptr, region_width, 1, dst->channels, src->byte_buffer.colorspace, false);
699 float_ptr += 4 * dst->x;
700 }
701
702 /* Perform alpha conversion. */
703 if (IMB_alpha_affects_rgb(src)) {
704 float_ptr = rect_float;
705 for (int i = 0; i < region_height; i++) {
706 IMB_premultiply_rect_float(float_ptr, dst->channels, region_width, 1);
707 float_ptr += 4 * dst->x;
708 }
709 }
710}
711
713{
714 /* verify if we byte and float buffers */
715 if (ibuf->byte_buffer.data == nullptr) {
716 return;
717 }
718
719 /* allocate float buffer outside of image buffer,
720 * so work-in-progress color space conversion doesn't
721 * interfere with other parts of blender
722 */
723 float *rect_float = ibuf->float_buffer.data;
724 if (rect_float == nullptr) {
725 rect_float = MEM_calloc_arrayN<float>(4 * IMB_get_pixel_count(ibuf), "IMB_float_from_byte");
726
727 if (rect_float == nullptr) {
728 return;
729 }
730
731 ibuf->channels = 4;
732
734 }
735
736 rcti region_to_update;
737 BLI_rcti_init(&region_to_update, 0, ibuf->x, 0, ibuf->y);
738 IMB_float_from_byte_ex(ibuf, ibuf, &region_to_update);
739}
740
742
743/* -------------------------------------------------------------------- */
746
748{
749 float *rct_fl = ibuf->float_buffer.data;
750 uchar *rct = ibuf->byte_buffer.data;
751 size_t i;
752
753 if (rct_fl) {
754 if (ibuf->channels >= 3) {
755 for (i = IMB_get_pixel_count(ibuf); i > 0; i--, rct_fl += ibuf->channels) {
756 rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
757 }
758 }
759 }
760
761 if (rct) {
762 for (i = IMB_get_pixel_count(ibuf); i > 0; i--, rct += 4) {
763 rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
764 }
765 }
766}
767
769
770/* -------------------------------------------------------------------- */
773
774void IMB_saturation(ImBuf *ibuf, float sat)
775{
776 using namespace blender;
777
778 const size_t pixel_count = IMB_get_pixel_count(ibuf);
779 if (ibuf->byte_buffer.data != nullptr) {
780 threading::parallel_for(IndexRange(pixel_count), 64 * 1024, [&](IndexRange range) {
781 uchar *ptr = ibuf->byte_buffer.data + range.first() * 4;
782 float rgb[3];
783 float hsv[3];
784 for ([[maybe_unused]] const int64_t i : range) {
786 rgb_to_hsv_v(rgb, hsv);
787 hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb + 0, rgb + 1, rgb + 2);
789 ptr += 4;
790 }
791 });
792 }
793
794 if (ibuf->float_buffer.data != nullptr && ibuf->channels >= 3) {
795 threading::parallel_for(IndexRange(pixel_count), 64 * 1024, [&](IndexRange range) {
796 const int channels = ibuf->channels;
797 float *ptr = ibuf->float_buffer.data + range.first() * channels;
798 float hsv[3];
799 for ([[maybe_unused]] const int64_t i : range) {
800 rgb_to_hsv_v(ptr, hsv);
801 hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], ptr + 0, ptr + 1, ptr + 2);
802 ptr += channels;
803 }
804 });
805 }
806}
807
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
MINLINE void srgb_to_linearrgb_uchar4_predivide(float linear[4], const unsigned char srgb[4])
MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linear[4])
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4])
void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b)
Definition math_color.cc:21
MINLINE float dither_random_value(int x, int y)
MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4])
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE void linearrgb_to_srgb_v4(float srgb[4], const float linear[4])
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4])
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4])
#define MINLINE
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.cc:414
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
unsigned char uchar
unsigned short ushort
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, const ColorSpace *colorspace, bool predivide)
void IMB_colormanagement_transform_float(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
@ COLOR_ROLE_DEFAULT_BYTE
@ COLOR_ROLE_SCENE_LINEAR
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
const char * IMB_colormanagement_role_colorspace_name_get(int role)
Function declarations for filter.cc.
#define FILTER_MASK_USED
Definition IMB_imbuf.hh:297
void IMB_assign_float_buffer(ImBuf *ibuf, float *buffer_data, ImBufOwnership ownership)
bool IMB_alloc_byte_pixels(ImBuf *ibuf, bool initialize_pixels=true)
size_t IMB_get_pixel_count(const ImBuf *ibuf)
Get the length of the data of the given image buffer in pixels.
#define IB_PROFILE_NONE
#define IB_PROFILE_SRGB
@ IB_RECT_INVALID
@ IB_TAKE_OWNERSHIP
#define IB_PROFILE_LINEAR_RGB
@ IB_alphamode_channel_packed
Read Guarded memory(de)allocation.
long long int int64_t
constexpr int64_t first() const
constexpr int64_t size() const
constexpr const char * c_str() const
virtual StringRefNull name() const =0
void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, int channels_from, int width, int height, int stride_to, int stride_from, char *mask)
#define USHORTTOFLOAT(val)
void IMB_float_from_byte_ex(ImBuf *dst, const ImBuf *src, const rcti *region_to_update)
MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], float dither, int x, int y)
Definition conversion.cc:55
MINLINE void ushort_to_byte_dither_v4(uchar b[4], const ushort us[4], float dither, int x, int y)
Definition conversion.cc:42
void IMB_buffer_byte_from_float_mask(uchar *rect_to, const float *rect_from, int channels_from, float dither, bool predivide, int width, int height, int stride_to, int stride_from, char *mask)
bool IMB_alpha_affects_rgb(const ImBuf *ibuf)
Definition conversion.cc:65
void IMB_byte_from_float(ImBuf *ibuf)
void IMB_buffer_float_from_float(float *rect_to, const float *rect_from, int channels_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
void IMB_color_to_bw(ImBuf *ibuf)
void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
void IMB_buffer_float_from_float_threaded(float *rect_to, const float *rect_from, int channels_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
void IMB_saturation(ImBuf *ibuf, float sat)
MINLINE uchar ftochar(float value)
Definition conversion.cc:37
MINLINE void ushort_to_byte_v4(uchar b[4], const ushort us[4])
Definition conversion.cc:29
void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from, int channels_from, float dither, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from, int start_y)
Definition conversion.cc:70
void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
void IMB_float_from_byte(ImBuf *ibuf)
void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition filter.cc:621
void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition filter.cc:559
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
MINLINE unsigned char unit_ushort_to_uchar(unsigned short val)
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
const ColorSpace * colorspace
const ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4227