Blender V4.3
divers.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
10#include "BLI_rect.h"
11#include "BLI_task.hh"
12#include "BLI_utildefines.h"
13
14#include "IMB_filter.hh"
15#include "IMB_imbuf.hh"
16#include "IMB_imbuf_types.hh"
17#include "imbuf.hh"
18
21
22#include "MEM_guardedalloc.h"
23
24/* -------------------------------------------------------------------- */
29 float dither;
30};
31
33{
34 DitherContext *di;
35
36 di = MEM_cnew<DitherContext>("dithering context");
37 di->dither = dither;
38
39 return di;
40}
41
43{
44 MEM_freeN(di);
45}
46
49/* -------------------------------------------------------------------- */
53MINLINE void ushort_to_byte_v4(uchar b[4], const ushort us[4])
54{
55 b[0] = unit_ushort_to_uchar(us[0]);
56 b[1] = unit_ushort_to_uchar(us[1]);
57 b[2] = unit_ushort_to_uchar(us[2]);
58 b[3] = unit_ushort_to_uchar(us[3]);
59}
60
61MINLINE uchar ftochar(float value)
62{
63 return unit_float_to_uchar_clamp(value);
64}
65
67 uchar b[4], const ushort us[4], DitherContext *di, float s, float t)
68{
69#define USHORTTOFLOAT(val) (float(val) / 65535.0f)
70 float dither_value = dither_random_value(s, t) * 0.0033f * di->dither;
71
72 b[0] = ftochar(dither_value + USHORTTOFLOAT(us[0]));
73 b[1] = ftochar(dither_value + USHORTTOFLOAT(us[1]));
74 b[2] = ftochar(dither_value + USHORTTOFLOAT(us[2]));
75 b[3] = unit_ushort_to_uchar(us[3]);
76
77#undef USHORTTOFLOAT
78}
79
81 uchar b[4], const float f[4], DitherContext *di, float s, float t)
82{
83 float dither_value = dither_random_value(s, t) * 0.0033f * di->dither;
84
85 b[0] = ftochar(dither_value + f[0]);
86 b[1] = ftochar(dither_value + f[1]);
87 b[2] = ftochar(dither_value + f[2]);
89}
90
92{
93 return ibuf && (ibuf->flags & IB_alphamode_channel_packed) == 0;
94}
95
97 const float *rect_from,
98 int channels_from,
99 float dither,
100 int profile_to,
101 int profile_from,
102 bool predivide,
103 int width,
104 int height,
105 int stride_to,
106 int stride_from)
107{
108 float tmp[4];
109 int x, y;
110 DitherContext *di = nullptr;
111 float inv_width = 1.0f / width;
112 float inv_height = 1.0f / height;
113
114 /* we need valid profiles */
115 BLI_assert(profile_to != IB_PROFILE_NONE);
116 BLI_assert(profile_from != IB_PROFILE_NONE);
117
118 if (dither) {
119 di = create_dither_context(dither);
120 }
121
122 for (y = 0; y < height; y++) {
123 float t = y * inv_height;
124
125 if (channels_from == 1) {
126 /* single channel input */
127 const float *from = rect_from + size_t(stride_from) * y;
128 uchar *to = rect_to + size_t(stride_to) * y * 4;
129
130 for (x = 0; x < width; x++, from++, to += 4) {
131 to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
132 }
133 }
134 else if (channels_from == 3) {
135 /* RGB input */
136 const float *from = rect_from + size_t(stride_from) * y * 3;
137 uchar *to = rect_to + size_t(stride_to) * y * 4;
138
139 if (profile_to == profile_from) {
140 /* no color space conversion */
141 for (x = 0; x < width; x++, from += 3, to += 4) {
142 rgb_float_to_uchar(to, from);
143 to[3] = 255;
144 }
145 }
146 else if (profile_to == IB_PROFILE_SRGB) {
147 /* convert from linear to sRGB */
148 for (x = 0; x < width; x++, from += 3, to += 4) {
149 linearrgb_to_srgb_v3_v3(tmp, from);
150 rgb_float_to_uchar(to, tmp);
151 to[3] = 255;
152 }
153 }
154 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
155 /* convert from sRGB to linear */
156 for (x = 0; x < width; x++, from += 3, to += 4) {
157 srgb_to_linearrgb_v3_v3(tmp, from);
158 rgb_float_to_uchar(to, tmp);
159 to[3] = 255;
160 }
161 }
162 }
163 else if (channels_from == 4) {
164 /* RGBA input */
165 const float *from = rect_from + size_t(stride_from) * y * 4;
166 uchar *to = rect_to + size_t(stride_to) * y * 4;
167
168 if (profile_to == profile_from) {
169 /* no color space conversion */
170 if (dither && predivide) {
171 float straight[4];
172 for (x = 0; x < width; x++, from += 4, to += 4) {
173 premul_to_straight_v4_v4(straight, from);
174 float_to_byte_dither_v4(to, straight, di, float(x) * inv_width, t);
175 }
176 }
177 else if (dither) {
178 for (x = 0; x < width; x++, from += 4, to += 4) {
179 float_to_byte_dither_v4(to, from, di, float(x) * inv_width, t);
180 }
181 }
182 else if (predivide) {
183 for (x = 0; x < width; x++, from += 4, to += 4) {
185 }
186 }
187 else {
188 for (x = 0; x < width; x++, from += 4, to += 4) {
189 rgba_float_to_uchar(to, from);
190 }
191 }
192 }
193 else if (profile_to == IB_PROFILE_SRGB) {
194 /* convert from linear to sRGB */
195 ushort us[4];
196 float straight[4];
197
198 if (dither && predivide) {
199 for (x = 0; x < width; x++, from += 4, to += 4) {
200 premul_to_straight_v4_v4(straight, from);
202 ushort_to_byte_dither_v4(to, us, di, float(x) * inv_width, t);
203 }
204 }
205 else if (dither) {
206 for (x = 0; x < width; x++, from += 4, to += 4) {
208 ushort_to_byte_dither_v4(to, us, di, float(x) * inv_width, t);
209 }
210 }
211 else if (predivide) {
212 for (x = 0; x < width; x++, from += 4, to += 4) {
213 premul_to_straight_v4_v4(straight, from);
215 ushort_to_byte_v4(to, us);
216 }
217 }
218 else {
219 for (x = 0; x < width; x++, from += 4, to += 4) {
221 ushort_to_byte_v4(to, us);
222 }
223 }
224 }
225 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
226 /* convert from sRGB to linear */
227 if (dither && predivide) {
228 for (x = 0; x < width; x++, from += 4, to += 4) {
230 float_to_byte_dither_v4(to, tmp, di, float(x) * inv_width, t);
231 }
232 }
233 else if (dither) {
234 for (x = 0; x < width; x++, from += 4, to += 4) {
235 srgb_to_linearrgb_v4(tmp, from);
236 float_to_byte_dither_v4(to, tmp, di, float(x) * inv_width, t);
237 }
238 }
239 else if (predivide) {
240 for (x = 0; x < width; x++, from += 4, to += 4) {
242 rgba_float_to_uchar(to, tmp);
243 }
244 }
245 else {
246 for (x = 0; x < width; x++, from += 4, to += 4) {
247 srgb_to_linearrgb_v4(tmp, from);
248 rgba_float_to_uchar(to, tmp);
249 }
250 }
251 }
252 }
253 }
254
255 if (dither) {
257 }
258}
259
261 const float *rect_from,
262 int channels_from,
263 float dither,
264 bool predivide,
265 int width,
266 int height,
267 int stride_to,
268 int stride_from,
269 char *mask)
270{
271 int x, y;
272 DitherContext *di = nullptr;
273 float inv_width = 1.0f / width, inv_height = 1.0f / height;
274
275 if (dither) {
276 di = create_dither_context(dither);
277 }
278
279 for (y = 0; y < height; y++) {
280 float t = y * inv_height;
281
282 if (channels_from == 1) {
283 /* single channel input */
284 const float *from = rect_from + size_t(stride_from) * y;
285 uchar *to = rect_to + size_t(stride_to) * y * 4;
286
287 for (x = 0; x < width; x++, from++, to += 4) {
288 if (*mask++ == FILTER_MASK_USED) {
289 to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
290 }
291 }
292 }
293 else if (channels_from == 3) {
294 /* RGB input */
295 const float *from = rect_from + size_t(stride_from) * y * 3;
296 uchar *to = rect_to + size_t(stride_to) * y * 4;
297
298 for (x = 0; x < width; x++, from += 3, to += 4) {
299 if (*mask++ == FILTER_MASK_USED) {
300 rgb_float_to_uchar(to, from);
301 to[3] = 255;
302 }
303 }
304 }
305 else if (channels_from == 4) {
306 /* RGBA input */
307 const float *from = rect_from + size_t(stride_from) * y * 4;
308 uchar *to = rect_to + size_t(stride_to) * y * 4;
309
310 if (dither && predivide) {
311 float straight[4];
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 }
325 }
326 else if (predivide) {
327 for (x = 0; x < width; x++, from += 4, to += 4) {
328 if (*mask++ == FILTER_MASK_USED) {
330 }
331 }
332 }
333 else {
334 for (x = 0; x < width; x++, from += 4, to += 4) {
335 if (*mask++ == FILTER_MASK_USED) {
336 rgba_float_to_uchar(to, from);
337 }
338 }
339 }
340 }
341 }
342
343 if (dither) {
345 }
346}
347
348void IMB_buffer_float_from_byte(float *rect_to,
349 const uchar *rect_from,
350 int profile_to,
351 int profile_from,
352 bool predivide,
353 int width,
354 int height,
355 int stride_to,
356 int stride_from)
357{
358 float tmp[4];
359 int x, y;
360
361 /* we need valid profiles */
362 BLI_assert(profile_to != IB_PROFILE_NONE);
363 BLI_assert(profile_from != IB_PROFILE_NONE);
364
365 /* RGBA input */
366 for (y = 0; y < height; y++) {
367 const uchar *from = rect_from + size_t(stride_from) * y * 4;
368 float *to = rect_to + size_t(stride_to) * y * 4;
369
370 if (profile_to == profile_from) {
371 /* no color space conversion */
372 for (x = 0; x < width; x++, from += 4, to += 4) {
373 rgba_uchar_to_float(to, from);
374 }
375 }
376 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
377 /* convert sRGB to linear */
378 if (predivide) {
379 for (x = 0; x < width; x++, from += 4, to += 4) {
381 }
382 }
383 else {
384 for (x = 0; x < width; x++, from += 4, to += 4) {
385 srgb_to_linearrgb_uchar4(to, from);
386 }
387 }
388 }
389 else if (profile_to == IB_PROFILE_SRGB) {
390 /* convert linear to sRGB */
391 if (predivide) {
392 for (x = 0; x < width; x++, from += 4, to += 4) {
393 rgba_uchar_to_float(tmp, from);
395 }
396 }
397 else {
398 for (x = 0; x < width; x++, from += 4, to += 4) {
399 rgba_uchar_to_float(tmp, from);
400 linearrgb_to_srgb_v4(to, tmp);
401 }
402 }
403 }
404 }
405}
406
407void IMB_buffer_float_from_float(float *rect_to,
408 const float *rect_from,
409 int channels_from,
410 int profile_to,
411 int profile_from,
412 bool predivide,
413 int width,
414 int height,
415 int stride_to,
416 int stride_from)
417{
418 int x, y;
419
420 /* we need valid profiles */
421 BLI_assert(profile_to != IB_PROFILE_NONE);
422 BLI_assert(profile_from != IB_PROFILE_NONE);
423
424 if (channels_from == 1) {
425 /* single channel input */
426 for (y = 0; y < height; y++) {
427 const float *from = rect_from + size_t(stride_from) * y;
428 float *to = rect_to + size_t(stride_to) * y * 4;
429
430 for (x = 0; x < width; x++, from++, to += 4) {
431 to[0] = to[1] = to[2] = to[3] = from[0];
432 }
433 }
434 }
435 else if (channels_from == 3) {
436 /* RGB input */
437 for (y = 0; y < height; y++) {
438 const float *from = rect_from + size_t(stride_from) * y * 3;
439 float *to = rect_to + size_t(stride_to) * y * 4;
440
441 if (profile_to == profile_from) {
442 /* no color space conversion */
443 for (x = 0; x < width; x++, from += 3, to += 4) {
444 copy_v3_v3(to, from);
445 to[3] = 1.0f;
446 }
447 }
448 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
449 /* convert from sRGB to linear */
450 for (x = 0; x < width; x++, from += 3, to += 4) {
451 srgb_to_linearrgb_v3_v3(to, from);
452 to[3] = 1.0f;
453 }
454 }
455 else if (profile_to == IB_PROFILE_SRGB) {
456 /* convert from linear to sRGB */
457 for (x = 0; x < width; x++, from += 3, to += 4) {
458 linearrgb_to_srgb_v3_v3(to, from);
459 to[3] = 1.0f;
460 }
461 }
462 }
463 }
464 else if (channels_from == 4) {
465 /* RGBA input */
466 for (y = 0; y < height; y++) {
467 const float *from = rect_from + size_t(stride_from) * y * 4;
468 float *to = rect_to + size_t(stride_to) * y * 4;
469
470 if (profile_to == profile_from) {
471 /* same profile, copy */
472 memcpy(to, from, sizeof(float) * size_t(4) * width);
473 }
474 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
475 /* convert to sRGB to linear */
476 if (predivide) {
477 for (x = 0; x < width; x++, from += 4, to += 4) {
479 }
480 }
481 else {
482 for (x = 0; x < width; x++, from += 4, to += 4) {
483 srgb_to_linearrgb_v4(to, from);
484 }
485 }
486 }
487 else if (profile_to == IB_PROFILE_SRGB) {
488 /* convert from linear to sRGB */
489 if (predivide) {
490 for (x = 0; x < width; x++, from += 4, to += 4) {
492 }
493 }
494 else {
495 for (x = 0; x < width; x++, from += 4, to += 4) {
496 linearrgb_to_srgb_v4(to, from);
497 }
498 }
499 }
500 }
501 }
502}
503
515
516static void imb_buffer_float_from_float_thread_do(void *data_v, int scanline)
517{
518 const int num_scanlines = 1;
520 size_t offset_from = size_t(scanline) * data->stride_from * data->channels_from;
521 size_t offset_to = size_t(scanline) * data->stride_to * data->channels_from;
522 IMB_buffer_float_from_float(data->rect_to + offset_to,
523 data->rect_from + offset_from,
524 data->channels_from,
525 data->profile_to,
526 data->profile_from,
527 data->predivide,
528 data->width,
529 num_scanlines,
530 data->stride_to,
531 data->stride_from);
532}
533
535 const float *rect_from,
536 int channels_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 if (size_t(width) * height < 64 * 64) {
547 rect_from,
548 channels_from,
549 profile_to,
550 profile_from,
551 predivide,
552 width,
553 height,
554 stride_to,
555 stride_from);
556 }
557 else {
559 data.rect_to = rect_to;
560 data.rect_from = rect_from;
561 data.channels_from = channels_from;
562 data.profile_to = profile_to;
563 data.profile_from = profile_from;
564 data.predivide = predivide;
565 data.width = width;
566 data.stride_to = stride_to;
567 data.stride_from = stride_from;
569 }
570}
571
573 const float *rect_from,
574 int channels_from,
575 int width,
576 int height,
577 int stride_to,
578 int stride_from,
579 char *mask)
580{
581 int x, y;
582
583 if (channels_from == 1) {
584 /* single channel input */
585 for (y = 0; y < height; y++) {
586 const float *from = rect_from + size_t(stride_from) * y;
587 float *to = rect_to + size_t(stride_to) * y * 4;
588
589 for (x = 0; x < width; x++, from++, to += 4) {
590 if (*mask++ == FILTER_MASK_USED) {
591 to[0] = to[1] = to[2] = to[3] = from[0];
592 }
593 }
594 }
595 }
596 else if (channels_from == 3) {
597 /* RGB input */
598 for (y = 0; y < height; y++) {
599 const float *from = rect_from + size_t(stride_from) * y * 3;
600 float *to = rect_to + size_t(stride_to) * y * 4;
601
602 for (x = 0; x < width; x++, from += 3, to += 4) {
603 if (*mask++ == FILTER_MASK_USED) {
604 copy_v3_v3(to, from);
605 to[3] = 1.0f;
606 }
607 }
608 }
609 }
610 else if (channels_from == 4) {
611 /* RGBA input */
612 for (y = 0; y < height; y++) {
613 const float *from = rect_from + size_t(stride_from) * y * 4;
614 float *to = rect_to + size_t(stride_to) * y * 4;
615
616 for (x = 0; x < width; x++, from += 4, to += 4) {
617 if (*mask++ == FILTER_MASK_USED) {
618 copy_v4_v4(to, from);
619 }
620 }
621 }
622 }
623}
624
626 const uchar *rect_from,
627 int profile_to,
628 int profile_from,
629 bool predivide,
630 int width,
631 int height,
632 int stride_to,
633 int stride_from)
634{
635 float tmp[4];
636 int x, y;
637
638 /* we need valid profiles */
639 BLI_assert(profile_to != IB_PROFILE_NONE);
640 BLI_assert(profile_from != IB_PROFILE_NONE);
641
642 /* always RGBA input */
643 for (y = 0; y < height; y++) {
644 const uchar *from = rect_from + size_t(stride_from) * y * 4;
645 uchar *to = rect_to + size_t(stride_to) * y * 4;
646
647 if (profile_to == profile_from) {
648 /* same profile, copy */
649 memcpy(to, from, sizeof(uchar[4]) * width);
650 }
651 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
652 /* convert to sRGB to linear */
653 if (predivide) {
654 for (x = 0; x < width; x++, from += 4, to += 4) {
655 rgba_uchar_to_float(tmp, from);
657 rgba_float_to_uchar(to, tmp);
658 }
659 }
660 else {
661 for (x = 0; x < width; x++, from += 4, to += 4) {
662 rgba_uchar_to_float(tmp, from);
663 srgb_to_linearrgb_v4(tmp, tmp);
664 rgba_float_to_uchar(to, tmp);
665 }
666 }
667 }
668 else if (profile_to == IB_PROFILE_SRGB) {
669 /* convert from linear to sRGB */
670 if (predivide) {
671 for (x = 0; x < width; x++, from += 4, to += 4) {
672 rgba_uchar_to_float(tmp, from);
674 rgba_float_to_uchar(to, tmp);
675 }
676 }
677 else {
678 for (x = 0; x < width; x++, from += 4, to += 4) {
679 rgba_uchar_to_float(tmp, from);
680 linearrgb_to_srgb_v4(tmp, tmp);
681 rgba_float_to_uchar(to, tmp);
682 }
683 }
684 }
685 }
686}
687
690/* -------------------------------------------------------------------- */
695{
696 /* verify we have a float buffer */
697 if (ibuf->float_buffer.data == nullptr) {
698 return;
699 }
700
701 /* create byte rect if it didn't exist yet */
702 if (ibuf->byte_buffer.data == nullptr) {
703 if (imb_addrectImBuf(ibuf, false) == 0) {
704 return;
705 }
706 }
707
708 const char *from_colorspace = (ibuf->float_buffer.colorspace == nullptr) ?
712 const char *to_colorspace = (ibuf->byte_buffer.colorspace == nullptr) ?
716
717 float *buffer = static_cast<float *>(MEM_dupallocN(ibuf->float_buffer.data));
718
719 /* first make float buffer in byte space */
720 const bool predivide = IMB_alpha_affects_rgb(ibuf);
722 buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, predivide);
723
724 /* convert from float's premul alpha to byte's straight alpha */
725 if (IMB_alpha_affects_rgb(ibuf)) {
726 IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y);
727 }
728
729 /* convert float to byte */
731 buffer,
732 ibuf->channels,
733 ibuf->dither,
736 false,
737 ibuf->x,
738 ibuf->y,
739 ibuf->x,
740 ibuf->x);
741
742 MEM_freeN(buffer);
743
744 /* ensure user flag is reset */
745 ibuf->userflags &= ~IB_RECT_INVALID;
746}
747
748void IMB_float_from_rect_ex(ImBuf *dst, const ImBuf *src, const rcti *region_to_update)
749{
750 BLI_assert_msg(dst->float_buffer.data != nullptr,
751 "Destination buffer should have a float buffer assigned.");
752 BLI_assert_msg(src->byte_buffer.data != nullptr,
753 "Source buffer should have a byte buffer assigned.");
754 BLI_assert_msg(dst->x == src->x, "Source and destination buffer should have the same dimension");
755 BLI_assert_msg(dst->y == src->y, "Source and destination buffer should have the same dimension");
756 BLI_assert_msg(dst->channels = 4, "Destination buffer should have 4 channels.");
757 BLI_assert_msg(region_to_update->xmin >= 0,
758 "Region to update should be clipped to the given buffers.");
759 BLI_assert_msg(region_to_update->ymin >= 0,
760 "Region to update should be clipped to the given buffers.");
761 BLI_assert_msg(region_to_update->xmax <= dst->x,
762 "Region to update should be clipped to the given buffers.");
763 BLI_assert_msg(region_to_update->ymax <= dst->y,
764 "Region to update should be clipped to the given buffers.");
765
766 float *rect_float = dst->float_buffer.data;
767 rect_float += (region_to_update->xmin + region_to_update->ymin * dst->x) * 4;
768 uchar *rect = src->byte_buffer.data;
769 rect += (region_to_update->xmin + region_to_update->ymin * dst->x) * 4;
770 const int region_width = BLI_rcti_size_x(region_to_update);
771 const int region_height = BLI_rcti_size_y(region_to_update);
772
773 /* Convert byte buffer to float buffer without color or alpha conversion. */
775 rect,
778 false,
779 region_width,
780 region_height,
781 src->x,
782 dst->x);
783
784 /* Perform color space conversion from rect color space to linear. */
785 float *float_ptr = rect_float;
786 for (int i = 0; i < region_height; i++) {
788 float_ptr, region_width, 1, dst->channels, src->byte_buffer.colorspace, false);
789 float_ptr += 4 * dst->x;
790 }
791
792 /* Perform alpha conversion. */
793 if (IMB_alpha_affects_rgb(src)) {
794 float_ptr = rect_float;
795 for (int i = 0; i < region_height; i++) {
796 IMB_premultiply_rect_float(float_ptr, dst->channels, region_width, 1);
797 float_ptr += 4 * dst->x;
798 }
799 }
800}
801
803{
804 /* verify if we byte and float buffers */
805 if (ibuf->byte_buffer.data == nullptr) {
806 return;
807 }
808
809 /* allocate float buffer outside of image buffer,
810 * so work-in-progress color space conversion doesn't
811 * interfere with other parts of blender
812 */
813 float *rect_float = ibuf->float_buffer.data;
814 if (rect_float == nullptr) {
815 const size_t size = IMB_get_rect_len(ibuf) * sizeof(float[4]);
816 rect_float = static_cast<float *>(MEM_callocN(size, "IMB_float_from_rect"));
817
818 if (rect_float == nullptr) {
819 return;
820 }
821
822 ibuf->channels = 4;
823
825 }
826
827 rcti region_to_update;
828 BLI_rcti_init(&region_to_update, 0, ibuf->x, 0, ibuf->y);
829 IMB_float_from_rect_ex(ibuf, ibuf, &region_to_update);
830}
831
834/* -------------------------------------------------------------------- */
839{
840 float *rct_fl = ibuf->float_buffer.data;
841 uchar *rct = ibuf->byte_buffer.data;
842 size_t i;
843
844 if (rct_fl) {
845 if (ibuf->channels >= 3) {
846 for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct_fl += ibuf->channels) {
847 rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
848 }
849 }
850 }
851
852 if (rct) {
853 for (i = IMB_get_rect_len(ibuf); i > 0; i--, rct += 4) {
854 rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
855 }
856 }
857}
858
861/* -------------------------------------------------------------------- */
865void IMB_saturation(ImBuf *ibuf, float sat)
866{
867 using namespace blender;
868
869 const size_t pixel_count = IMB_get_rect_len(ibuf);
870 if (ibuf->byte_buffer.data != nullptr) {
871 threading::parallel_for(IndexRange(pixel_count), 64 * 1024, [&](IndexRange range) {
872 uchar *ptr = ibuf->byte_buffer.data + range.first() * 4;
873 float rgb[3];
874 float hsv[3];
875 for ([[maybe_unused]] const int64_t i : range) {
877 rgb_to_hsv_v(rgb, hsv);
878 hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb + 0, rgb + 1, rgb + 2);
880 ptr += 4;
881 }
882 });
883 }
884
885 if (ibuf->float_buffer.data != nullptr && ibuf->channels >= 3) {
886 threading::parallel_for(IndexRange(pixel_count), 64 * 1024, [&](IndexRange range) {
887 const int channels = ibuf->channels;
888 float *ptr = ibuf->float_buffer.data + range.first() * channels;
889 float hsv[3];
890 for ([[maybe_unused]] const int64_t i : range) {
891 rgb_to_hsv_v(ptr, hsv);
892 hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], ptr + 0, ptr + 1, ptr + 2);
893 ptr += channels;
894 }
895 });
896 }
897}
898
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
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 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 float dither_random_value(float s, float t)
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:193
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
unsigned char uchar
unsigned short ushort
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3])
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
const char * IMB_colormanagement_role_colorspace_name_get(int role)
@ COLOR_ROLE_DEFAULT_BYTE
@ COLOR_ROLE_SCENE_LINEAR
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, ColorSpace *colorspace, bool predivide)
Function declarations for filter.cc.
size_t IMB_get_rect_len(const ImBuf *ibuf)
Get the length of the rect of the given image buffer in terms of pixels.
#define FILTER_MASK_USED
Definition IMB_imbuf.hh:378
void IMB_assign_float_buffer(ImBuf *ibuf, float *buffer_data, ImBufOwnership ownership)
void IMB_processor_apply_threaded_scanlines(int total_scanlines, ScanlineThreadFunc do_thread, void *custom_data)
bool imb_addrectImBuf(ImBuf *ibuf, bool initialize_pixels=true)
Contains defines and structs used throughout the imbuf module.
#define IB_PROFILE_NONE
#define IB_PROFILE_SRGB
@ IB_TAKE_OWNERSHIP
#define IB_PROFILE_LINEAR_RGB
@ IB_alphamode_channel_packed
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
local_group_size(16, 16) .push_constant(Type b
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)
Definition divers.cc:572
#define USHORTTOFLOAT(val)
void IMB_rect_from_float(ImBuf *ibuf)
Definition divers.cc:694
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)
Definition divers.cc:96
void IMB_float_from_rect_ex(ImBuf *dst, const ImBuf *src, const rcti *region_to_update)
Definition divers.cc:748
MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], DitherContext *di, float s, float t)
Definition divers.cc:80
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)
Definition divers.cc:260
bool IMB_alpha_affects_rgb(const ImBuf *ibuf)
Definition divers.cc:91
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)
Definition divers.cc:407
static DitherContext * create_dither_context(float dither)
Definition divers.cc:32
void IMB_color_to_bw(ImBuf *ibuf)
Definition divers.cc:838
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)
Definition divers.cc:348
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)
Definition divers.cc:534
void IMB_saturation(ImBuf *ibuf, float sat)
Definition divers.cc:865
MINLINE uchar ftochar(float value)
Definition divers.cc:61
MINLINE void ushort_to_byte_v4(uchar b[4], const ushort us[4])
Definition divers.cc:53
static void imb_buffer_float_from_float_thread_do(void *data_v, int scanline)
Definition divers.cc:516
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)
Definition divers.cc:625
static void clear_dither_context(DitherContext *di)
Definition divers.cc:42
void IMB_float_from_rect(ImBuf *ibuf)
Definition divers.cc:802
MINLINE void ushort_to_byte_dither_v4(uchar b[4], const ushort us[4], DitherContext *di, float s, float t)
Definition divers.cc:66
void IMB_unpremultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition filter.cc:623
void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition filter.cc:561
IndexRange range
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
#define unit_float_to_uchar_clamp(val)
#define unit_ushort_to_uchar(val)
__int64 int64_t
Definition stdint.h:89
char name[MAX_COLORSPACE_NAME]
float dither
Definition divers.cc:29
const float * rect_from
Definition divers.cc:506
ColorSpace * colorspace
ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
int ymin
int ymax
int xmin
int xmax
PointerRNA * ptr
Definition wm_files.cc:4126