Blender V4.3
image_save.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cerrno>
10#include <cstring>
11
12#include "BLI_fileops.h"
13#include "BLI_index_range.hh"
14#include "BLI_listbase.h"
15#include "BLI_path_utils.hh"
16#include "BLI_string.h"
17#include "BLI_task.hh"
18#include "BLI_vector.hh"
19
20#include "BLT_translation.hh"
21
22#include "DNA_image_types.h"
23
24#include "MEM_guardedalloc.h"
25
27#include "IMB_imbuf.hh"
28#include "IMB_imbuf_types.hh"
29#include "IMB_openexr.hh"
30
31#include "BKE_colortools.hh"
32#include "BKE_global.hh"
33#include "BKE_image.hh"
34#include "BKE_image_format.hh"
35#include "BKE_image_save.hh"
36#include "BKE_main.hh"
37#include "BKE_report.hh"
38#include "BKE_scene.hh"
39
40#include "RE_pipeline.h"
41
42using blender::Vector;
43
44static char imtype_best_depth(ImBuf *ibuf, const char imtype)
45{
46 const char depth_ok = BKE_imtype_valid_depths(imtype);
47
48 if (ibuf->float_buffer.data) {
49 if (depth_ok & R_IMF_CHAN_DEPTH_32) {
51 }
52 if (depth_ok & R_IMF_CHAN_DEPTH_24) {
54 }
55 if (depth_ok & R_IMF_CHAN_DEPTH_16) {
57 }
58 if (depth_ok & R_IMF_CHAN_DEPTH_12) {
60 }
61 return R_IMF_CHAN_DEPTH_8;
62 }
63
64 if (depth_ok & R_IMF_CHAN_DEPTH_8) {
65 return R_IMF_CHAN_DEPTH_8;
66 }
67 if (depth_ok & R_IMF_CHAN_DEPTH_12) {
69 }
70 if (depth_ok & R_IMF_CHAN_DEPTH_16) {
72 }
73 if (depth_ok & R_IMF_CHAN_DEPTH_24) {
75 }
76 if (depth_ok & R_IMF_CHAN_DEPTH_32) {
78 }
79 return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
80}
81
83 Main *bmain,
84 Scene *scene,
85 Image *ima,
86 ImageUser *iuser,
87 const bool guess_path,
88 const bool save_as_render)
89{
90 /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
91 ImageUser save_iuser;
92 if (iuser == nullptr) {
93 BKE_imageuser_default(&save_iuser);
94 iuser = &save_iuser;
95 iuser->scene = scene;
96 }
97
98 memset(opts, 0, sizeof(*opts));
99
100 opts->bmain = bmain;
101 opts->scene = scene;
102 opts->save_as_render = ima->source == IMA_SRC_VIEWER || save_as_render;
103
104 BKE_image_format_init(&opts->im_format, false);
105
106 void *lock;
107 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
108
109 if (ibuf) {
110 bool is_depth_set = false;
111 const char *ima_colorspace = ima->colorspace_settings.name;
112
113 if (opts->save_as_render) {
114 /* Render/compositor output or user chose to save with render settings. */
115 BKE_image_format_init_for_write(&opts->im_format, scene, nullptr);
116 is_depth_set = true;
117 if (!BKE_image_is_multiview(ima)) {
118 /* In case multiview is disabled,
119 * render settings would be invalid for render result in this area. */
122 }
123 }
124 else {
126 if (ima->source == IMA_SRC_GENERATED &&
128 {
130 }
131
132 /* use the multiview image settings as the default */
135
136 /* Render output: colorspace from render settings. */
138 }
139
140 /* Default to saving in the same colorspace as the image setting. */
141 if (!opts->save_as_render) {
142 STRNCPY(opts->im_format.linear_colorspace_settings.name, ima_colorspace);
143 }
144
146
147 /* Compute filepath, but don't resolve multiview and UDIM which are handled
148 * by the image saving code itself. */
149 BKE_image_user_file_path_ex(bmain, iuser, ima, opts->filepath, false, false);
150
151 /* sanitize all settings */
152
153 /* unlikely but just in case */
156 }
157
158 /* depth, account for float buffer and format support */
159 if (is_depth_set == false) {
160 opts->im_format.depth = imtype_best_depth(ibuf, opts->im_format.imtype);
161 }
162
163 /* some formats don't use quality so fallback to scenes quality */
164 if (opts->im_format.quality == 0) {
165 opts->im_format.quality = scene->r.im_format.quality;
166 }
167
168 /* check for empty path */
169 if (guess_path && opts->filepath[0] == 0) {
170 const bool is_prev_save = !STREQ(G.filepath_last_image, "//");
171 if (opts->save_as_render) {
172 if (is_prev_save) {
173 STRNCPY(opts->filepath, G.filepath_last_image);
174 }
175 else {
176 BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"));
178 }
179 }
180 else {
181 BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2);
184 is_prev_save ? G.filepath_last_image : BKE_main_blendfile_path(bmain));
185 }
186
187 /* append UDIM marker if not present */
188 if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == nullptr) {
189 int len = strlen(opts->filepath);
190 STR_CONCAT(opts->filepath, len, ".<UDIM>");
191 }
192 }
193 }
194
195 /* Copy for detecting UI changes. */
197 opts->prev_imtype = opts->im_format.imtype;
198
199 BKE_image_release_ibuf(ima, ibuf, lock);
200
201 return (ibuf != nullptr);
202}
203
205{
206 /* Auto update color space when changing save as render and file type. */
207 if (opts->save_as_render) {
208 if (!opts->prev_save_as_render) {
210 BKE_image_format_init_for_write(&opts->im_format, opts->scene, nullptr);
211 }
212 else {
214 }
215 }
216 }
217 else {
218 if (opts->prev_save_as_render) {
219 /* Copy colorspace from image settings. */
221 &image->colorspace_settings);
222 }
223 else if (opts->im_format.imtype != opts->prev_imtype) {
225 }
226 }
227
229 opts->prev_imtype = opts->im_format.imtype;
230}
231
236
238 const char *filepath,
239 const ImageSaveOptions *opts)
240{
241 if (opts->do_newpath) {
242 STRNCPY(ima->filepath, filepath);
243
244 /* only image path, never ibuf */
245 if (opts->relative) {
246 const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
247 BLI_path_rel(ima->filepath, relbase); /* only after saving */
248 }
249 }
250}
251
252static void image_save_post(ReportList *reports,
253 Image *ima,
254 ImBuf *ibuf,
255 int ok,
256 const ImageSaveOptions *opts,
257 const bool save_copy,
258 const char *filepath,
259 bool *r_colorspace_changed)
260{
261 if (!ok) {
262 BKE_reportf(reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
263 return;
264 }
265
266 if (save_copy) {
267 return;
268 }
269
270 if (opts->do_newpath) {
271 STRNCPY(ibuf->filepath, filepath);
272 }
273
274 /* The tiled image code-path must call this on its own. */
275 if (ima->source != IMA_SRC_TILED) {
276 image_save_update_filepath(ima, filepath, opts);
277 }
278
279 ibuf->userflags &= ~IB_BITMAPDIRTY;
280
281 /* change type? */
282 if (ima->type == IMA_TYPE_R_RESULT) {
283 ima->type = IMA_TYPE_IMAGE;
284
285 /* workaround to ensure the render result buffer is no longer used
286 * by this image, otherwise can crash when a new render result is
287 * created. */
288 imb_freerectImBuf(ibuf);
290 }
292 ima->source = IMA_SRC_FILE;
293 ima->type = IMA_TYPE_IMAGE;
294 ImageTile *base_tile = BKE_image_get_tile(ima, 0);
295 base_tile->gen_flag &= ~IMA_GEN_TILE;
296 }
297
298 /* Update image file color space when saving to another color space. */
299 const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype);
300
301 if (!opts->save_as_render || linear_float_output) {
305 {
308 *r_colorspace_changed = true;
309 }
310 }
311}
312
313static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
314{
315 if (colormanaged_ibuf != ibuf) {
316 /* This guys might be modified by image buffer write functions,
317 * need to copy them back from color managed image buffer to an
318 * original one, so file type of image is being properly updated.
319 */
320 ibuf->ftype = colormanaged_ibuf->ftype;
321 ibuf->foptions = colormanaged_ibuf->foptions;
322 ibuf->planes = colormanaged_ibuf->planes;
323
324 IMB_freeImBuf(colormanaged_ibuf);
325 }
326}
327
334static bool image_save_single(ReportList *reports,
335 Image *ima,
336 ImageUser *iuser,
337 const ImageSaveOptions *opts,
338 bool *r_colorspace_changed)
339{
340 void *lock;
341 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
342 RenderResult *rr = nullptr;
343 bool ok = false;
344
345 if (ibuf == nullptr || (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.data == nullptr))
346 {
347 BKE_image_release_ibuf(ima, ibuf, lock);
348 return ok;
349 }
350
351 ImBuf *colormanaged_ibuf = nullptr;
352 const bool save_copy = opts->save_copy;
353 const bool save_as_render = opts->save_as_render;
354 const ImageFormatData *imf = &opts->im_format;
355
356 if (ima->type == IMA_TYPE_R_RESULT) {
357 /* enforce user setting for RGB or RGBA, but skip BW */
358 if (opts->im_format.planes == R_IMF_PLANES_RGBA) {
360 }
361 else if (opts->im_format.planes == R_IMF_PLANES_RGB) {
362 ibuf->planes = R_IMF_PLANES_RGB;
363 }
364 }
365 else {
366 /* TODO: better solution, if a 24bit image is painted onto it may contain alpha. */
367 if ((opts->im_format.planes == R_IMF_PLANES_RGBA) &&
368 /* it has been painted onto */
369 (ibuf->userflags & IB_BITMAPDIRTY))
370 {
371 /* checks each pixel, not ideal */
373 }
374 }
375
376 /* we need renderresult for exr and rendered multiview */
377 rr = BKE_image_acquire_renderresult(opts->scene, ima);
378 const bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 :
379 BLI_listbase_count_at_most(&ima->views, 2) < 2;
380 const bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
382 const bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
383 const int layer = (iuser && !is_multilayer) ? iuser->layer : -1;
384
385 /* error handling */
386 if (rr == nullptr) {
387 if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
388 BKE_report(reports, RPT_ERROR, "Did not write, no Multilayer Image");
389 BKE_image_release_ibuf(ima, ibuf, lock);
390 return ok;
391 }
392 }
393 else {
395 if (!BKE_image_is_stereo(ima)) {
396 BKE_reportf(reports,
397 RPT_ERROR,
398 R"(Did not write, the image doesn't have a "%s" and "%s" views)",
401 BKE_image_release_ibuf(ima, ibuf, lock);
403 return ok;
404 }
405
406 /* It shouldn't ever happen. */
407 if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == nullptr) ||
408 (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == nullptr))
409 {
410 BKE_reportf(reports,
411 RPT_ERROR,
412 R"(Did not write, the image doesn't have a "%s" and "%s" views)",
415 BKE_image_release_ibuf(ima, ibuf, lock);
417 return ok;
418 }
419 }
420 BKE_imbuf_stamp_info(rr, ibuf);
421 }
422
423 /* fancy multiview OpenEXR */
424 if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
425 /* save render result */
427 reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
428 image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
429 BKE_image_release_ibuf(ima, ibuf, lock);
430 }
431 /* regular mono pipeline */
432 else if (is_mono) {
433 if (is_exr_rr) {
435 reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
436 }
437 else {
438 colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
439 ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy);
440 imbuf_save_post(ibuf, colormanaged_ibuf);
441 }
442 image_save_post(reports,
443 ima,
444 ibuf,
445 ok,
446 opts,
447 (is_exr_rr ? true : save_copy),
448 opts->filepath,
449 r_colorspace_changed);
450 BKE_image_release_ibuf(ima, ibuf, lock);
451 }
452 /* individual multiview images */
453 else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
454 uchar planes = ibuf->planes;
455 const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
456
457 if (!is_exr_rr) {
458 BKE_image_release_ibuf(ima, ibuf, lock);
459 }
460
461 for (int i = 0; i < totviews; i++) {
462 char filepath[FILE_MAX];
463 bool ok_view = false;
464 const char *view = rr ? ((RenderView *)BLI_findlink(&rr->views, i))->name :
465 ((ImageView *)BLI_findlink(&ima->views, i))->name;
466
467 if (is_exr_rr) {
468 BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
470 reports, rr, filepath, imf, save_as_render, view, layer);
471 image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
472 }
473 else {
474 /* copy iuser to get the correct ibuf for this view */
475 ImageUser view_iuser;
476
477 if (iuser) {
478 /* copy iuser to get the correct ibuf for this view */
479 view_iuser = *iuser;
480 }
481 else {
482 BKE_imageuser_default(&view_iuser);
483 }
484
485 view_iuser.view = i;
486 view_iuser.flag &= ~IMA_SHOW_STEREO;
487
488 if (rr) {
489 BKE_image_multilayer_index(rr, &view_iuser);
490 }
491 else {
492 BKE_image_multiview_index(ima, &view_iuser);
493 }
494
495 ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
496 ibuf->planes = planes;
497
498 BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
499
500 colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
501 ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy);
502 imbuf_save_post(ibuf, colormanaged_ibuf);
503 image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
504 BKE_image_release_ibuf(ima, ibuf, lock);
505 }
506 ok &= ok_view;
507 }
508
509 if (is_exr_rr) {
510 BKE_image_release_ibuf(ima, ibuf, lock);
511 }
512 }
513 /* stereo (multiview) images */
514 else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
515 if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
517 reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
518 image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
519 BKE_image_release_ibuf(ima, ibuf, lock);
520 }
521 else {
522 ImBuf *ibuf_stereo[2] = {nullptr};
523
524 uchar planes = ibuf->planes;
525 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
526
527 /* we need to get the specific per-view buffers */
528 BKE_image_release_ibuf(ima, ibuf, lock);
529 bool stereo_ok = true;
530
531 for (int i = 0; i < 2; i++) {
532 ImageUser view_iuser;
533
534 if (iuser) {
535 view_iuser = *iuser;
536 }
537 else {
538 BKE_imageuser_default(&view_iuser);
539 }
540
541 view_iuser.flag &= ~IMA_SHOW_STEREO;
542
543 if (rr) {
544 int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
545 view_iuser.view = id;
546 BKE_image_multilayer_index(rr, &view_iuser);
547 }
548 else {
549 view_iuser.view = i;
550 BKE_image_multiview_index(ima, &view_iuser);
551 }
552
553 ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
554
555 if (ibuf == nullptr) {
557 reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
558 BKE_image_release_ibuf(ima, ibuf, lock);
559 stereo_ok = false;
560 break;
561 }
562
563 ibuf->planes = planes;
564
565 /* color manage the ImBuf leaving it ready for saving */
566 colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
567
568 BKE_image_format_to_imbuf(colormanaged_ibuf, imf);
569
570 /* duplicate buffer to prevent locker issue when using render result */
571 ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
572
573 imbuf_save_post(ibuf, colormanaged_ibuf);
574
575 BKE_image_release_ibuf(ima, ibuf, lock);
576 }
577
578 if (stereo_ok) {
579 ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
580
581 /* save via traditional path */
582 ok = BKE_imbuf_write_as(ibuf, opts->filepath, imf, save_copy);
583
584 IMB_freeImBuf(ibuf);
585 }
586
587 for (int i = 0; i < 2; i++) {
588 IMB_freeImBuf(ibuf_stereo[i]);
589 }
590 }
591 }
592
593 if (rr) {
595 }
596
597 return ok;
598}
599
601 ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts)
602{
603 /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
604 ImageUser save_iuser;
605 if (iuser == nullptr) {
606 BKE_imageuser_default(&save_iuser);
607 iuser = &save_iuser;
608 iuser->scene = opts->scene;
609 }
610
611 bool colorspace_changed = false;
612
613 eUDIM_TILE_FORMAT tile_format;
614 char *udim_pattern = nullptr;
615
616 if (ima->source == IMA_SRC_TILED) {
617 /* Verify filepath for tiled images contains a valid UDIM marker. */
618 udim_pattern = BKE_image_get_tile_strformat(opts->filepath, &tile_format);
619 if (tile_format == UDIM_TILE_FORMAT_NONE) {
620 BKE_reportf(reports,
621 RPT_ERROR,
622 "When saving a tiled image, the path '%s' must contain a valid UDIM marker",
623 opts->filepath);
624 return false;
625 }
626 }
627
628 /* Save images */
629 bool ok = false;
630 if (ima->source != IMA_SRC_TILED) {
631 ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
632 }
633 else {
634 /* Save all the tiles. */
636 ImageSaveOptions tile_opts = *opts;
638 tile_opts.filepath, udim_pattern, tile_format, tile->tile_number);
639
640 iuser->tile = tile->tile_number;
641 ok = image_save_single(reports, ima, iuser, &tile_opts, &colorspace_changed);
642 if (!ok) {
643 break;
644 }
645 }
646
647 /* Set the image path and clear the per-tile generated flag only if all tiles were ok. */
648 if (ok) {
650 tile->gen_flag &= ~IMA_GEN_TILE;
651 }
652 image_save_update_filepath(ima, opts->filepath, opts);
653 }
654 MEM_freeN(udim_pattern);
655 }
656
657 if (colorspace_changed) {
658 BKE_image_signal(bmain, ima, nullptr, IMA_SIGNAL_COLORMANAGE);
659 }
660
661 return ok;
662}
663
664/* OpenEXR saving, single and multilayer. */
665
667 const int width,
668 const int height,
669 const int channels,
670 const ImageFormatData *imf,
671 Vector<float *> &tmp_output_rects)
672{
673 if (imf == nullptr) {
674 return rect;
675 }
676
677 const char *to_colorspace = imf->linear_colorspace_settings.name;
678 if (to_colorspace[0] == '\0' || IMB_colormanagement_space_name_is_scene_linear(to_colorspace)) {
679 return rect;
680 }
681
682 float *output_rect = (float *)MEM_dupallocN(rect);
683 tmp_output_rects.append(output_rect);
684
685 const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(
688 output_rect, width, height, channels, from_colorspace, to_colorspace, false);
689
690 return output_rect;
691}
692
694 float *input_buffer, int width, int height, int channels, Vector<float *> &temporary_buffers)
695{
696 float *gray_scale_output = static_cast<float *>(
697 MEM_malloc_arrayN(width * height, sizeof(float), "Gray Scale Buffer For EXR"));
698 temporary_buffers.append(gray_scale_output);
699
701 blender::IndexRange(height), 1, [&](const blender::IndexRange sub_y_range) {
702 for (const int64_t y : sub_y_range) {
703 for (const int64_t x : blender::IndexRange(width)) {
704 const int64_t index = y * int64_t(width) + x;
705 gray_scale_output[index] = IMB_colormanagement_get_luminance(input_buffer +
706 index * channels);
707 }
708 }
709 });
710
711 return gray_scale_output;
712}
713
714static float *image_exr_opaque_alpha_buffer(int width,
715 int height,
716 Vector<float *> &temporary_buffers)
717{
718 float *alpha_output = static_cast<float *>(
719 MEM_malloc_arrayN(width * height, sizeof(float), "Opaque Alpha Buffer For EXR"));
720 temporary_buffers.append(alpha_output);
721
723 blender::IndexRange(height), 1, [&](const blender::IndexRange sub_y_range) {
724 for (const int64_t y : sub_y_range) {
725 for (const int64_t x : blender::IndexRange(width)) {
726 alpha_output[y * int64_t(width) + x] = 1.0;
727 }
728 }
729 });
730
731 return alpha_output;
732}
733
734static void add_exr_compositing_result(void *exr_handle,
735 const RenderResult *render_result,
736 const ImageFormatData *imf,
737 bool save_as_render,
738 const char *view_name,
739 int layer,
740 Vector<float *> &temporary_buffers)
741{
742 /* Render result has no compositing result. */
743 if (!render_result->have_combined) {
744 return;
745 }
746
747 /* Skip compositing result if we are saving a single layer EXR that is not the compositing
748 * layer, which always has the layer index of 0. */
749 const bool is_multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR);
750 if (!is_multi_layer && layer != 0) {
751 return;
752 }
753
754 /* Write the compositing result for the view with the given view name, or for all views if no
755 * view name is given. */
756 LISTBASE_FOREACH (RenderView *, render_view, &render_result->views) {
757 if (!render_view->ibuf || !render_view->ibuf->float_buffer.data) {
758 continue;
759 }
760
761 /* If a view name is given, then we skip views that do not match the given view name.
762 * Otherwise, we always add the views. */
763 if (view_name && !STREQ(view_name, render_view->name)) {
764 continue;
765 }
766
767 /* If a view name is given, that means we are writing a single view, so no need to identify the
768 * channel by the view name, and we supply an empty view to the rest of the code. */
769 const char *render_view_name = view_name ? "" : render_view->name;
770
771 /* Compositing results is always a 4-channel RGBA. */
772 const int channels_count_in_buffer = 4;
773 float *output_buffer = (save_as_render) ? image_exr_from_scene_linear_to_output(
774 render_view->ibuf->float_buffer.data,
775 render_result->rectx,
776 render_result->recty,
777 channels_count_in_buffer,
778 imf,
779 temporary_buffers) :
780 render_view->ibuf->float_buffer.data;
781
782 /* For multi-layer EXRs, we write the buffer as is with all its 4 channels. */
783 const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16);
784 if (is_multi_layer) {
785 for (int i = 0; i < channels_count_in_buffer; i++) {
786 char passname[EXR_PASS_MAXNAME];
787 RE_render_result_full_channel_name(passname, nullptr, "Combined", nullptr, "RGBA", i);
788 IMB_exr_add_channel(exr_handle,
789 "Composite",
790 passname,
791 render_view_name,
792 channels_count_in_buffer,
793 channels_count_in_buffer * render_result->rectx,
794 output_buffer + i,
795 half_float);
796 }
797 continue;
798 }
799
800 /* For single layer EXR, we only add the channels specified in the image format and do any
801 * needed color format conversion.
802 *
803 * In case of a single required channel, we need to do RGBA to BW conversion. */
804 const int required_channels = imf ? imf->planes / 8 : 4;
805 if (required_channels == 1) {
806 float *gray_scale_output = image_exr_from_rgb_to_bw(output_buffer,
807 render_result->rectx,
808 render_result->recty,
809 channels_count_in_buffer,
810 temporary_buffers);
811 IMB_exr_add_channel(exr_handle,
812 "",
813 "V",
814 render_view_name,
815 1,
816 render_result->rectx,
817 gray_scale_output,
818 half_float);
819 continue;
820 }
821
822 /* Add RGB[A] channels. This will essentially skip the alpha channel if only three channels
823 * were required. */
824 for (int i = 0; i < required_channels; i++) {
825 IMB_exr_add_channel(exr_handle,
826 "",
827 std::string(1, "RGBA"[i]).c_str(),
828 render_view_name,
829 channels_count_in_buffer,
830 channels_count_in_buffer * render_result->rectx,
831 output_buffer + i,
832 half_float);
833 }
834 }
835}
836
838 const RenderResult *rr,
839 const char *filepath,
840 const ImageFormatData *imf,
841 const bool save_as_render,
842 const char *view,
843 int layer)
844{
845 void *exrhandle = IMB_exr_get_handle();
846 const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR);
847
848 /* Write first layer if not multilayer and no layer was specified. */
849 if (!multi_layer && layer == -1) {
850 layer = 0;
851 }
852
853 /* First add views since IMB_exr_add_channel checks number of views. */
854 const RenderView *first_rview = (const RenderView *)rr->views.first;
855 if (first_rview && (first_rview->next || first_rview->name[0])) {
856 LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
857 if (!view || STREQ(view, rview->name)) {
858 IMB_exr_add_view(exrhandle, rview->name);
859 }
860 }
861 }
862
863 Vector<float *> tmp_output_rects;
864 add_exr_compositing_result(exrhandle, rr, imf, save_as_render, view, layer, tmp_output_rects);
865
866 /* Other render layers. */
867 int nr = (rr->have_combined) ? 1 : 0;
868 const bool has_multiple_layers = BLI_listbase_count_at_most(&rr->layers, 2) > 1;
869 LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
870 /* Skip other render layers if requested. */
871 if (!multi_layer && nr != layer) {
872 nr++;
873 continue;
874 }
875 nr++;
876
877 LISTBASE_FOREACH (RenderPass *, render_pass, &rl->passes) {
878 /* Skip non-RGBA and Z passes if not using multi layer. */
879 if (!multi_layer && !STR_ELEM(render_pass->name, RE_PASSNAME_COMBINED, "")) {
880 continue;
881 }
882
883 /* Skip pass if it does not match the requested view(s). */
884 const char *viewname = render_pass->view;
885 if (view) {
886 if (!STREQ(view, viewname)) {
887 continue;
888 }
889
890 viewname = "";
891 }
892
893 /* We only store RGBA passes as half float, for
894 * others precision loss can be problematic. */
895 const bool pass_RGBA = RE_RenderPassIsColor(render_pass);
896 const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16);
897 const bool pass_half_float = half_float && pass_RGBA;
898
899 /* Color-space conversion only happens on RGBA passes. */
900 float *output_rect = (save_as_render && pass_RGBA) ?
902 render_pass->ibuf->float_buffer.data,
903 rr->rectx,
904 rr->recty,
905 render_pass->channels,
906 imf,
907 tmp_output_rects) :
908 render_pass->ibuf->float_buffer.data;
909
910 /* For multi-layer EXRs, we write the pass as is with all of its channels. */
911 if (multi_layer) {
912 for (int i = 0; i < render_pass->channels; i++) {
913 char passname[EXR_PASS_MAXNAME];
914 char layname[EXR_PASS_MAXNAME];
915
916 /* A single unnamed layer indicates that the pass name should be used as the layer name,
917 * while the pass name should be the channel ID. */
918 if (!has_multiple_layers && rl->name[0] == '\0') {
919 passname[0] = render_pass->chan_id[i];
920 passname[1] = '\0';
921 STRNCPY(layname, render_pass->name);
922 }
923 else {
925 passname, nullptr, render_pass->name, nullptr, render_pass->chan_id, i);
926 STRNCPY(layname, rl->name);
927 }
928
929 IMB_exr_add_channel(exrhandle,
930 layname,
931 passname,
932 viewname,
933 render_pass->channels,
934 render_pass->channels * rr->rectx,
935 output_rect + i,
936 pass_half_float);
937 }
938 continue;
939 }
940
941 /* For single layer EXR, we only add the channels specified in the image format and do any
942 * needed color format conversion.
943 *
944 * First, if the required channels equal the pass channels, we add the channels as is. Or,
945 * we add the RGB[A] channels if the pass is RGB[A] and we require RGB[A]. If the alpha
946 * channel is required but does not exist in the pass, it will be added below. */
947 const int required_channels = imf ? imf->planes / 8 : 4;
948 if (required_channels == render_pass->channels ||
949 (required_channels != 1 && render_pass->channels != 1))
950 {
951 for (int i = 0; i < std::min(required_channels, render_pass->channels); i++) {
952 IMB_exr_add_channel(exrhandle,
953 "",
954 std::string(1, render_pass->chan_id[i]).c_str(),
955 viewname,
956 render_pass->channels,
957 render_pass->channels * rr->rectx,
958 output_rect + i,
959 pass_half_float);
960 }
961 }
962 else if (required_channels == 1) {
963 /* In case of a single required channel, we need to do RGB[A] to BW conversion. We know the
964 * input is RGB[A] and not single channel because it filed the condition above. */
965 float *gray_scale_output = image_exr_from_rgb_to_bw(
966 output_rect, rr->rectx, rr->recty, render_pass->channels, tmp_output_rects);
968 exrhandle, "", "V", viewname, 1, rr->rectx, gray_scale_output, pass_half_float);
969 }
970 else if (render_pass->channels == 1) {
971 /* In case of a single channel pass, we need to broadcast the same channel for each of the
972 * RGB channels that are required. We know the RGB is required because single channel
973 * requirement was handled above. The alpha channel will be added later. */
974 for (int i = 0; i < 3; i++) {
975 IMB_exr_add_channel(exrhandle,
976 "",
977 std::string(1, "RGB"[i]).c_str(),
978 viewname,
979 1,
980 rr->rectx,
981 output_rect,
982 pass_half_float);
983 }
984 }
985
986 /* Add an opaque alpha channel if the pass contains no alpha channel but an alpha channel is
987 * required. */
988 if (required_channels == 4 && render_pass->channels < 4) {
989 float *alpha_output = image_exr_opaque_alpha_buffer(
990 rr->rectx, rr->recty, tmp_output_rects);
992 exrhandle, "", "A", viewname, 1, rr->rectx, alpha_output, pass_half_float);
993 }
994 }
995 }
996
997 errno = 0;
998
1000
1001 int compress = (imf ? imf->exr_codec : 0);
1002 bool success = IMB_exr_begin_write(
1003 exrhandle, filepath, rr->rectx, rr->recty, compress, rr->stamp_data);
1004 if (success) {
1005 IMB_exr_write_channels(exrhandle);
1006 }
1007 else {
1008 /* TODO: get the error from openexr's exception. */
1010 reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno));
1011 }
1012
1013 for (float *rect : tmp_output_rects) {
1014 MEM_freeN(rect);
1015 }
1016
1017 IMB_exr_close(exrhandle);
1018 return success;
1019}
1020
1021/* Render output. */
1022
1024 const char *filepath,
1025 int ok,
1026 int err)
1027{
1028 if (ok) {
1029 /* no need to report, just some helpful console info */
1030 if (!G.quiet) {
1031 printf("Saved: '%s'\n", filepath);
1032 }
1033 }
1034 else {
1035 /* report on error since users will want to know what failed */
1037 reports, RPT_ERROR, "Render error (%s) cannot save: '%s'", strerror(err), filepath);
1038 }
1039}
1040
1042 const Scene *scene,
1043 const RenderResult *rr,
1044 ImBuf *ibuf,
1045 const char *filepath,
1046 const ImageFormatData *imf,
1047 const bool stamp)
1048{
1049 bool ok;
1050
1051 if (stamp) {
1052 /* writes the name of the individual cameras */
1053 ok = BKE_imbuf_write_stamp(scene, rr, ibuf, filepath, imf);
1054 }
1055 else {
1056 ok = BKE_imbuf_write(ibuf, filepath, imf);
1057 }
1058
1059 image_render_print_save_message(reports, filepath, ok, errno);
1060
1061 return ok;
1062}
1063
1065 RenderResult *rr,
1066 const Scene *scene,
1067 const bool stamp,
1068 const char *filepath_basis,
1069 const ImageFormatData *format,
1070 bool save_as_render)
1071{
1072 bool ok = true;
1073
1074 if (!rr) {
1075 return false;
1076 }
1077
1078 ImageFormatData image_format;
1079 BKE_image_format_init_for_write(&image_format, scene, format);
1080
1081 if (!save_as_render) {
1083 &format->linear_colorspace_settings);
1084 }
1085
1086 const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
1087 const bool is_exr_rr = ELEM(
1090 const float dither = scene->r.dither_intensity;
1091
1092 if (image_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
1094 reports, rr, filepath_basis, &image_format, save_as_render, nullptr, -1);
1095 image_render_print_save_message(reports, filepath_basis, ok, errno);
1096 }
1097
1098 /* mono, legacy code */
1099 else if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
1100 int view_id = 0;
1101 for (const RenderView *rv = (const RenderView *)rr->views.first; rv; rv = rv->next, view_id++)
1102 {
1103 char filepath[FILE_MAX];
1104 if (is_mono) {
1105 STRNCPY(filepath, filepath_basis);
1106 }
1107 else {
1108 BKE_scene_multiview_view_filepath_get(&scene->r, filepath_basis, rv->name, filepath);
1109 }
1110
1111 if (is_exr_rr) {
1113 reports, rr, filepath, &image_format, save_as_render, rv->name, -1);
1114 image_render_print_save_message(reports, filepath, ok, errno);
1115
1116 /* optional preview images for exr */
1117 if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
1118 image_format.imtype = R_IMF_IMTYPE_JPEG90;
1119 image_format.depth = R_IMF_CHAN_DEPTH_8;
1120
1121 if (BLI_path_extension_check(filepath, ".exr")) {
1122 filepath[strlen(filepath) - 4] = 0;
1123 }
1124 BKE_image_path_ext_from_imformat_ensure(filepath, sizeof(filepath), &image_format);
1125
1126 ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
1127 ibuf->planes = 24;
1128 IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, false, &image_format);
1129
1131 reports, scene, rr, ibuf, filepath, &image_format, stamp);
1132
1133 IMB_freeImBuf(ibuf);
1134 }
1135 }
1136 else {
1137 ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
1138
1139 IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, false, &image_format);
1140
1142 reports, scene, rr, ibuf, filepath, &image_format, stamp);
1143
1144 /* imbuf knows which rects are not part of ibuf */
1145 IMB_freeImBuf(ibuf);
1146 }
1147 }
1148 }
1149 else { /* R_IMF_VIEWS_STEREO_3D */
1151
1152 char filepath[FILE_MAX];
1153 STRNCPY(filepath, filepath_basis);
1154
1155 if (image_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
1156 printf("Stereo 3D not supported for MultiLayer image: %s\n", filepath);
1157 }
1158 else {
1159 ImBuf *ibuf_arr[3] = {nullptr};
1160 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
1161 int i;
1162
1163 for (i = 0; i < 2; i++) {
1164 int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
1165 ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
1166 IMB_colormanagement_imbuf_for_write(ibuf_arr[i], save_as_render, false, &image_format);
1167 }
1168
1169 ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]);
1170
1172 reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
1173
1174 /* optional preview images for exr */
1175 if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
1176 image_format.imtype = R_IMF_IMTYPE_JPEG90;
1177 image_format.depth = R_IMF_CHAN_DEPTH_8;
1178
1179 if (BLI_path_extension_check(filepath, ".exr")) {
1180 filepath[strlen(filepath) - 4] = 0;
1181 }
1182
1183 BKE_image_path_ext_from_imformat_ensure(filepath, sizeof(filepath), &image_format);
1184 ibuf_arr[2]->planes = 24;
1185
1187 reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
1188 }
1189
1190 /* imbuf knows which rects are not part of ibuf */
1191 for (i = 0; i < 3; i++) {
1192 IMB_freeImBuf(ibuf_arr[i]);
1193 }
1194 }
1195 }
1196
1197 BKE_image_format_free(&image_format);
1198
1199 return ok;
1200}
void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings *colorspace_settings, const ColorManagedColorspaceSettings *settings)
bool BKE_color_managed_colorspace_settings_equals(const ColorManagedColorspaceSettings *settings1, const ColorManagedColorspaceSettings *settings2)
eUDIM_TILE_FORMAT
Definition BKE_image.hh:422
@ UDIM_TILE_FORMAT_NONE
Definition BKE_image.hh:423
void BKE_imbuf_stamp_info(const RenderResult *rr, ImBuf *ibuf)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
char * BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format)
void BKE_image_set_filepath_from_tile_number(char *filepath, const char *pattern, eUDIM_TILE_FORMAT tile_format, int tile_number)
RenderPass * BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_image_release_renderresult(Scene *scene, Image *ima, RenderResult *render_result)
void BKE_image_user_file_path_ex(const Main *bmain, const ImageUser *iuser, const Image *ima, char *filepath, const bool resolve_udim, const bool resolve_multiview)
#define IMA_SIGNAL_COLORMANAGE
Definition BKE_image.hh:143
bool BKE_imbuf_alpha_test(ImBuf *ibuf)
void BKE_imageuser_default(ImageUser *iuser)
bool BKE_image_is_stereo(const Image *ima)
bool BKE_image_is_multiview(const Image *ima)
bool BKE_imbuf_write(ImBuf *ibuf, const char *filepath, const ImageFormatData *imf)
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
bool BKE_imbuf_write_stamp(const Scene *scene, const RenderResult *rr, ImBuf *ibuf, const char *filepath, const ImageFormatData *imf)
bool BKE_imbuf_write_as(ImBuf *ibuf, const char *filepath, const ImageFormatData *imf, bool save_copy)
RenderResult * BKE_image_acquire_renderresult(Scene *scene, Image *ima)
void BKE_image_multiview_index(const Image *ima, ImageUser *iuser)
void BKE_image_format_free(ImageFormatData *imf)
void BKE_image_format_init(ImageFormatData *imf, const bool render)
void BKE_image_format_init_for_write(ImageFormatData *imf, const Scene *scene_src, const ImageFormatData *imf_src)
void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
int BKE_image_path_ext_from_imformat_ensure(char *filepath, size_t filepath_maxncpy, const ImageFormatData *im_format)
void BKE_image_format_update_color_space_for_type(ImageFormatData *format)
void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
void BKE_image_format_color_management_copy_from_scene(ImageFormatData *imf, const Scene *scene)
char BKE_imtype_valid_depths(char imtype)
bool BKE_imtype_requires_linear_float(char imtype)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_scene_multiview_view_filepath_get(const RenderData *rd, const char *filepath, const char *view, char *r_filepath)
Definition scene.cc:3104
#define BLI_assert(a)
Definition BLI_assert.h:50
File and directory operations.
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count_at_most(const struct ListBase *listbase, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_findstringindex(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1)
#define FILE_MAX
#define BLI_path_join(...)
bool BLI_path_extension_check(const char *path, const char *ext) ATTR_NONNULL(1
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
#define STR_ELEM(...)
Definition BLI_string.h:653
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define STR_CONCAT(dst, len, suffix)
Definition BLI_string.h:602
unsigned char uchar
#define ELEM(...)
#define STREQ(a, b)
#define DATA_(msgid)
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:647
@ IMA_GEN_TILE
@ IMA_SRC_FILE
@ IMA_SRC_GENERATED
@ IMA_SRC_VIEWER
@ IMA_SRC_TILED
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ IMA_TYPE_IMAGE
@ IMA_SHOW_STEREO
#define RE_PASSNAME_COMBINED
#define STEREO_LEFT_NAME
@ R_IMF_FLAG_PREVIEW_JPG
@ R_IMF_IMTYPE_JPEG90
@ R_IMF_IMTYPE_OPENEXR
@ R_IMF_IMTYPE_MULTILAYER
@ R_IMF_VIEWS_MULTIVIEW
@ R_IMF_VIEWS_STEREO_3D
@ R_IMF_VIEWS_INDIVIDUAL
@ R_IMF_PLANES_RGB
@ R_IMF_PLANES_RGBA
@ R_IMF_PLANES_BW
@ R_IMF_CHAN_DEPTH_24
@ R_IMF_CHAN_DEPTH_8
@ R_IMF_CHAN_DEPTH_16
@ R_IMF_CHAN_DEPTH_12
@ R_IMF_CHAN_DEPTH_32
#define STEREO_RIGHT_NAME
@ R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE
static AppView * view
@ COLOR_ROLE_DEFAULT_BYTE
@ COLOR_ROLE_SCENE_LINEAR
bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
ImBuf * IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, const ImageFormatData *image_format)
bool IMB_colormanagement_space_name_is_data(const char *name)
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
const char * IMB_colormanagement_role_colorspace_name_get(int role)
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
void imb_freerectImBuf(ImBuf *ibuf)
void imb_freerectfloatImBuf(ImBuf *ibuf)
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
ImBuf * IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
Contains defines and structs used throughout the imbuf module.
@ IB_BITMAPDIRTY
bool IMB_exr_begin_write(void *handle, const char *filepath, int width, int height, int compress, const StampData *stamp)
void IMB_exr_add_view(void *handle, const char *name)
void IMB_exr_close(void *handle)
#define EXR_PASS_MAXNAME
void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, const char *viewname, int xstride, int ystride, float *rect, bool use_half_float)
void IMB_exr_write_channels(void *handle)
void * IMB_exr_get_handle()
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
volatile int lock
void append(const T &value)
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
#define printf
#define offsetof(t, d)
int len
void IMB_freeImBuf(ImBuf *)
bool BKE_image_save(ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts)
static float * image_exr_from_scene_linear_to_output(float *rect, const int width, const int height, const int channels, const ImageFormatData *imf, Vector< float * > &tmp_output_rects)
static void image_save_post(ReportList *reports, Image *ima, ImBuf *ibuf, int ok, const ImageSaveOptions *opts, const bool save_copy, const char *filepath, bool *r_colorspace_changed)
static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
bool BKE_image_render_write_exr(ReportList *reports, const RenderResult *rr, const char *filepath, const ImageFormatData *imf, const bool save_as_render, const char *view, int layer)
static bool image_render_write_stamp_test(ReportList *reports, const Scene *scene, const RenderResult *rr, ImBuf *ibuf, const char *filepath, const ImageFormatData *imf, const bool stamp)
static char imtype_best_depth(ImBuf *ibuf, const char imtype)
Definition image_save.cc:44
bool BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene, Image *ima, ImageUser *iuser, const bool guess_path, const bool save_as_render)
Definition image_save.cc:82
static float * image_exr_from_rgb_to_bw(float *input_buffer, int width, int height, int channels, Vector< float * > &temporary_buffers)
static bool image_save_single(ReportList *reports, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts, bool *r_colorspace_changed)
static float * image_exr_opaque_alpha_buffer(int width, int height, Vector< float * > &temporary_buffers)
static void image_render_print_save_message(ReportList *reports, const char *filepath, int ok, int err)
static void image_save_update_filepath(Image *ima, const char *filepath, const ImageSaveOptions *opts)
bool BKE_image_render_write(ReportList *reports, RenderResult *rr, const Scene *scene, const bool stamp, const char *filepath_basis, const ImageFormatData *format, bool save_as_render)
void BKE_image_save_options_update(ImageSaveOptions *opts, const Image *image)
static void add_exr_compositing_result(void *exr_handle, const RenderResult *render_result, const ImageFormatData *imf, bool save_as_render, const char *view_name, int layer, Vector< float * > &temporary_buffers)
void BKE_image_save_options_free(ImageSaveOptions *opts)
ccl_global const KernelWorkTile * tile
format
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
#define G(x, y, z)
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:95
bool RE_RenderPassIsColor(const RenderPass *render_pass)
bool RE_HasFloatPixels(const RenderResult *result)
ImBuf * RE_render_result_rect_to_ibuf(RenderResult *rr, const ImageFormatData *imf, const float dither, const int view_id)
void RE_render_result_full_channel_name(char *fullname, const char *layname, const char *passname, const char *viewname, const char *chan_id, const int channel)
__int64 int64_t
Definition stdint.h:89
char name[66]
Definition DNA_ID.h:425
char filepath[IMB_FILEPATH_SIZE]
ImBufFloatBuffer float_buffer
ImbFormatOptions foptions
ImBufByteBuffer byte_buffer
unsigned char planes
enum eImbFileType ftype
ColorManagedColorspaceSettings linear_colorspace_settings
Stereo3dFormat stereo3d_format
ImageFormatData im_format
struct Scene * scene
ColorManagedColorspaceSettings colorspace_settings
char views_format
char filepath[1024]
ListBase tiles
short source
ListBase views
struct Stereo3dFormat * stereo3d_format
void * first
struct ImageFormatData im_format
float dither_intensity
ListBase views
ListBase layers
struct StampData * stamp_data
struct RenderView * next
Definition RE_pipeline.h:46
char name[64]
Definition RE_pipeline.h:47
struct RenderData r
void * BKE_image_get_tile
Definition stubs.c:36