Blender  V3.3
image_save.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include <cerrno>
9 #include <cstring>
10 
11 #include "BLI_listbase.h"
12 #include "BLI_path_util.h"
13 #include "BLI_string.h"
14 #include "BLI_vector.hh"
15 
16 #include "DNA_image_types.h"
17 
18 #include "MEM_guardedalloc.h"
19 
20 #include "IMB_colormanagement.h"
21 #include "IMB_imbuf.h"
22 #include "IMB_imbuf_types.h"
23 #include "IMB_openexr.h"
24 
25 #include "BKE_colortools.h"
26 #include "BKE_global.h"
27 #include "BKE_image.h"
28 #include "BKE_image_format.h"
29 #include "BKE_image_save.h"
30 #include "BKE_main.h"
31 #include "BKE_report.h"
32 #include "BKE_scene.h"
33 
34 #include "RE_pipeline.h"
35 
36 using blender::Vector;
37 
38 static char imtype_best_depth(ImBuf *ibuf, const char imtype)
39 {
40  const char depth_ok = BKE_imtype_valid_depths(imtype);
41 
42  if (ibuf->rect_float) {
43  if (depth_ok & R_IMF_CHAN_DEPTH_32) {
44  return R_IMF_CHAN_DEPTH_32;
45  }
46  if (depth_ok & R_IMF_CHAN_DEPTH_24) {
47  return R_IMF_CHAN_DEPTH_24;
48  }
49  if (depth_ok & R_IMF_CHAN_DEPTH_16) {
50  return R_IMF_CHAN_DEPTH_16;
51  }
52  if (depth_ok & R_IMF_CHAN_DEPTH_12) {
53  return R_IMF_CHAN_DEPTH_12;
54  }
55  return R_IMF_CHAN_DEPTH_8;
56  }
57 
58  if (depth_ok & R_IMF_CHAN_DEPTH_8) {
59  return R_IMF_CHAN_DEPTH_8;
60  }
61  if (depth_ok & R_IMF_CHAN_DEPTH_12) {
62  return R_IMF_CHAN_DEPTH_12;
63  }
64  if (depth_ok & R_IMF_CHAN_DEPTH_16) {
65  return R_IMF_CHAN_DEPTH_16;
66  }
67  if (depth_ok & R_IMF_CHAN_DEPTH_24) {
68  return R_IMF_CHAN_DEPTH_24;
69  }
70  if (depth_ok & R_IMF_CHAN_DEPTH_32) {
71  return R_IMF_CHAN_DEPTH_32;
72  }
73  return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
74 }
75 
77  Main *bmain,
78  Scene *scene,
79  Image *ima,
80  ImageUser *iuser,
81  const bool guess_path,
82  const bool save_as_render)
83 {
84  /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
85  ImageUser save_iuser;
86  if (iuser == nullptr) {
87  BKE_imageuser_default(&save_iuser);
88  iuser = &save_iuser;
89  iuser->scene = scene;
90  }
91 
92  memset(opts, 0, sizeof(*opts));
93 
94  opts->bmain = bmain;
95  opts->scene = scene;
96  opts->save_as_render = ima->source == IMA_SRC_VIEWER || save_as_render;
97 
98  BKE_image_format_init(&opts->im_format, false);
99 
100  void *lock;
101  ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
102 
103  if (ibuf) {
104  Scene *scene = opts->scene;
105  bool is_depth_set = false;
106  const char *ima_colorspace = ima->colorspace_settings.name;
107 
108  if (opts->save_as_render) {
109  /* Render/compositor output or user chose to save with render settings. */
111  is_depth_set = true;
112  if (!BKE_image_is_multiview(ima)) {
113  /* In case multiview is disabled,
114  * render settings would be invalid for render result in this area. */
116  opts->im_format.views_format = ima->views_format;
117  }
118  }
119  else {
121  if (ima->source == IMA_SRC_GENERATED &&
122  !IMB_colormanagement_space_name_is_data(ima_colorspace)) {
124  }
125 
126  /* use the multiview image settings as the default */
128  opts->im_format.views_format = ima->views_format;
129 
130  /* Render output: colorspace from render settings. */
132  }
133 
134  /* Default to saving in the same colorspace as the image setting. */
135  if (!opts->save_as_render) {
136  STRNCPY(opts->im_format.linear_colorspace_settings.name, ima_colorspace);
137  }
138 
140 
141  /* Compute filepath, but don't resolve multiview and UDIM which are handled
142  * by the image saving code itself. */
143  BKE_image_user_file_path_ex(bmain, iuser, ima, opts->filepath, false, false);
144 
145  /* sanitize all settings */
146 
147  /* unlikely but just in case */
150  }
151 
152  /* depth, account for float buffer and format support */
153  if (is_depth_set == false) {
154  opts->im_format.depth = imtype_best_depth(ibuf, opts->im_format.imtype);
155  }
156 
157  /* some formats don't use quality so fallback to scenes quality */
158  if (opts->im_format.quality == 0) {
160  }
161 
162  /* check for empty path */
163  if (guess_path && opts->filepath[0] == 0) {
164  const bool is_prev_save = !STREQ(G.ima, "//");
165  if (opts->save_as_render) {
166  if (is_prev_save) {
167  BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
168  }
169  else {
170  BLI_strncpy(opts->filepath, "//untitled", sizeof(opts->filepath));
172  }
173  }
174  else {
175  BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2);
177  BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
178  }
179 
180  /* append UDIM marker if not present */
181  if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == nullptr) {
182  int len = strlen(opts->filepath);
183  STR_CONCAT(opts->filepath, len, ".<UDIM>");
184  }
185  }
186  }
187 
188  /* Copy for detecting UI changes. */
189  opts->prev_save_as_render = opts->save_as_render;
190  opts->prev_imtype = opts->im_format.imtype;
191 
192  BKE_image_release_ibuf(ima, ibuf, lock);
193 
194  return (ibuf != nullptr);
195 }
196 
198 {
199  /* Auto update color space when changing save as render and file type. */
200  if (opts->save_as_render) {
201  if (!opts->prev_save_as_render) {
203  BKE_image_format_init_for_write(&opts->im_format, opts->scene, nullptr);
204  }
205  else {
207  }
208  }
209  }
210  else {
211  if (opts->prev_save_as_render) {
212  /* Copy colorspace from image settings. */
214  &image->colorspace_settings);
215  }
216  else if (opts->im_format.imtype != opts->prev_imtype &&
219  const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype);
220 
221  /* TODO: detect if the colorspace is linear, not just equal to scene linear. */
222  const bool is_linear = IMB_colormanagement_space_name_is_scene_linear(
224 
225  /* If changing to a linear float or byte format, ensure we have a compatible color space. */
226  if (linear_float_output && !is_linear) {
229  }
230  else if (!linear_float_output && is_linear) {
233  }
234  }
235  }
236 
237  opts->prev_save_as_render = opts->save_as_render;
238  opts->prev_imtype = opts->im_format.imtype;
239 }
240 
242 {
244 }
245 
247  const char *filepath,
248  const ImageSaveOptions *opts)
249 {
250  if (opts->do_newpath) {
251  BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
252 
253  /* only image path, never ibuf */
254  if (opts->relative) {
255  const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
256  BLI_path_rel(ima->filepath, relbase); /* only after saving */
257  }
258  }
259 }
260 
261 static void image_save_post(ReportList *reports,
262  Image *ima,
263  ImBuf *ibuf,
264  int ok,
265  const ImageSaveOptions *opts,
266  int save_copy,
267  const char *filepath,
268  bool *r_colorspace_changed)
269 {
270  if (!ok) {
271  BKE_reportf(reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
272  return;
273  }
274 
275  if (save_copy) {
276  return;
277  }
278 
279  if (opts->do_newpath) {
280  BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
281  }
282 
283  /* The tiled image code-path must call this on its own. */
284  if (ima->source != IMA_SRC_TILED) {
285  image_save_update_filepath(ima, filepath, opts);
286  }
287 
288  ibuf->userflags &= ~IB_BITMAPDIRTY;
289 
290  /* change type? */
291  if (ima->type == IMA_TYPE_R_RESULT) {
292  ima->type = IMA_TYPE_IMAGE;
293 
294  /* workaround to ensure the render result buffer is no longer used
295  * by this image, otherwise can crash when a new render result is
296  * created. */
297  if (ibuf->rect && !(ibuf->mall & IB_rect)) {
298  imb_freerectImBuf(ibuf);
299  }
300  if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat)) {
302  }
303  if (ibuf->zbuf && !(ibuf->mall & IB_zbuf)) {
304  IMB_freezbufImBuf(ibuf);
305  }
306  if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat)) {
308  }
309  }
311  ima->source = IMA_SRC_FILE;
312  ima->type = IMA_TYPE_IMAGE;
313  }
314 
315  /* Update image file color space when saving to another color space. */
316  const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype);
317 
318  if (!opts->save_as_render || linear_float_output) {
324  *r_colorspace_changed = true;
325  }
326  }
327 }
328 
329 static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
330 {
331  if (colormanaged_ibuf != ibuf) {
332  /* This guys might be modified by image buffer write functions,
333  * need to copy them back from color managed image buffer to an
334  * original one, so file type of image is being properly updated.
335  */
336  ibuf->ftype = colormanaged_ibuf->ftype;
337  ibuf->foptions = colormanaged_ibuf->foptions;
338  ibuf->planes = colormanaged_ibuf->planes;
339 
340  IMB_freeImBuf(colormanaged_ibuf);
341  }
342 }
343 
349 static bool image_save_single(ReportList *reports,
350  Image *ima,
351  ImageUser *iuser,
352  const ImageSaveOptions *opts,
353  bool *r_colorspace_changed)
354 {
355  void *lock;
356  ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
357  RenderResult *rr = nullptr;
358  bool ok = false;
359 
360  if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
361  BKE_image_release_ibuf(ima, ibuf, lock);
362  return ok;
363  }
364 
365  ImBuf *colormanaged_ibuf = nullptr;
366  const bool save_copy = opts->save_copy;
367  const bool save_as_render = opts->save_as_render;
368  const ImageFormatData *imf = &opts->im_format;
369 
370  if (ima->type == IMA_TYPE_R_RESULT) {
371  /* enforce user setting for RGB or RGBA, but skip BW */
372  if (opts->im_format.planes == R_IMF_PLANES_RGBA) {
373  ibuf->planes = R_IMF_PLANES_RGBA;
374  }
375  else if (opts->im_format.planes == R_IMF_PLANES_RGB) {
376  ibuf->planes = R_IMF_PLANES_RGB;
377  }
378  }
379  else {
380  /* TODO: better solution, if a 24bit image is painted onto it may contain alpha. */
381  if ((opts->im_format.planes == R_IMF_PLANES_RGBA) &&
382  /* it has been painted onto */
383  (ibuf->userflags & IB_BITMAPDIRTY)) {
384  /* checks each pixel, not ideal */
386  }
387  }
388 
389  /* we need renderresult for exr and rendered multiview */
390  rr = BKE_image_acquire_renderresult(opts->scene, ima);
391  const bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 :
392  BLI_listbase_count_at_most(&ima->views, 2) < 2;
393  const bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
394  RE_HasFloatPixels(rr);
395  const bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
396  const int layer = (iuser && !is_multilayer) ? iuser->layer : -1;
397 
398  /* error handling */
399  if (rr == nullptr) {
400  if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
401  BKE_report(reports, RPT_ERROR, "Did not write, no Multilayer Image");
402  BKE_image_release_ibuf(ima, ibuf, lock);
403  return ok;
404  }
405  }
406  else {
407  if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
408  if (!BKE_image_is_stereo(ima)) {
409  BKE_reportf(reports,
410  RPT_ERROR,
411  R"(Did not write, the image doesn't have a "%s" and "%s" views)",
414  BKE_image_release_ibuf(ima, ibuf, lock);
416  return ok;
417  }
418 
419  /* It shouldn't ever happen. */
420  if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == nullptr) ||
421  (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == nullptr)) {
422  BKE_reportf(reports,
423  RPT_ERROR,
424  R"(Did not write, the image doesn't have a "%s" and "%s" views)",
427  BKE_image_release_ibuf(ima, ibuf, lock);
429  return ok;
430  }
431  }
432  BKE_imbuf_stamp_info(rr, ibuf);
433  }
434 
435  /* fancy multiview OpenEXR */
436  if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
437  /* save render result */
439  reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
440  image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
441  BKE_image_release_ibuf(ima, ibuf, lock);
442  }
443  /* regular mono pipeline */
444  else if (is_mono) {
445  if (is_exr_rr) {
447  reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
448  }
449  else {
450  colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
451  ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy);
452  imbuf_save_post(ibuf, colormanaged_ibuf);
453  }
454  image_save_post(reports,
455  ima,
456  ibuf,
457  ok,
458  opts,
459  (is_exr_rr ? true : save_copy),
460  opts->filepath,
461  r_colorspace_changed);
462  BKE_image_release_ibuf(ima, ibuf, lock);
463  }
464  /* individual multiview images */
465  else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
466  unsigned char planes = ibuf->planes;
467  const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
468 
469  if (!is_exr_rr) {
470  BKE_image_release_ibuf(ima, ibuf, lock);
471  }
472 
473  for (int i = 0; i < totviews; i++) {
474  char filepath[FILE_MAX];
475  bool ok_view = false;
476  const char *view = rr ? ((RenderView *)BLI_findlink(&rr->views, i))->name :
477  ((ImageView *)BLI_findlink(&ima->views, i))->name;
478 
479  if (is_exr_rr) {
480  BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
481  ok_view = BKE_image_render_write_exr(
482  reports, rr, filepath, imf, save_as_render, view, layer);
483  image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
484  }
485  else {
486  /* copy iuser to get the correct ibuf for this view */
487  ImageUser view_iuser;
488 
489  if (iuser) {
490  /* copy iuser to get the correct ibuf for this view */
491  view_iuser = *iuser;
492  }
493  else {
494  BKE_imageuser_default(&view_iuser);
495  }
496 
497  view_iuser.view = i;
498  view_iuser.flag &= ~IMA_SHOW_STEREO;
499 
500  if (rr) {
501  BKE_image_multilayer_index(rr, &view_iuser);
502  }
503  else {
504  BKE_image_multiview_index(ima, &view_iuser);
505  }
506 
507  ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
508  ibuf->planes = planes;
509 
510  BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
511 
512  colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
513  ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy);
514  imbuf_save_post(ibuf, colormanaged_ibuf);
515  image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
516  BKE_image_release_ibuf(ima, ibuf, lock);
517  }
518  ok &= ok_view;
519  }
520 
521  if (is_exr_rr) {
522  BKE_image_release_ibuf(ima, ibuf, lock);
523  }
524  }
525  /* stereo (multiview) images */
526  else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
527  if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
529  reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
530  image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
531  BKE_image_release_ibuf(ima, ibuf, lock);
532  }
533  else {
534  ImBuf *ibuf_stereo[2] = {nullptr};
535 
536  unsigned char planes = ibuf->planes;
537  const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
538 
539  /* we need to get the specific per-view buffers */
540  BKE_image_release_ibuf(ima, ibuf, lock);
541  bool stereo_ok = true;
542 
543  for (int i = 0; i < 2; i++) {
544  ImageUser view_iuser;
545 
546  if (iuser) {
547  view_iuser = *iuser;
548  }
549  else {
550  BKE_imageuser_default(&view_iuser);
551  }
552 
553  view_iuser.flag &= ~IMA_SHOW_STEREO;
554 
555  if (rr) {
556  int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
557  view_iuser.view = id;
558  BKE_image_multilayer_index(rr, &view_iuser);
559  }
560  else {
561  view_iuser.view = i;
562  BKE_image_multiview_index(ima, &view_iuser);
563  }
564 
565  ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
566 
567  if (ibuf == nullptr) {
568  BKE_report(
569  reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
570  BKE_image_release_ibuf(ima, ibuf, lock);
571  stereo_ok = false;
572  break;
573  }
574 
575  ibuf->planes = planes;
576 
577  /* color manage the ImBuf leaving it ready for saving */
578  colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
579 
580  BKE_image_format_to_imbuf(colormanaged_ibuf, imf);
581 
582  /* duplicate buffer to prevent locker issue when using render result */
583  ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
584 
585  imbuf_save_post(ibuf, colormanaged_ibuf);
586 
587  BKE_image_release_ibuf(ima, ibuf, lock);
588  }
589 
590  if (stereo_ok) {
591  ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
592 
593  /* save via traditional path */
594  ok = BKE_imbuf_write_as(ibuf, opts->filepath, imf, save_copy);
595 
596  IMB_freeImBuf(ibuf);
597  }
598 
599  for (int i = 0; i < 2; i++) {
600  IMB_freeImBuf(ibuf_stereo[i]);
601  }
602  }
603  }
604 
605  if (rr) {
607  }
608 
609  return ok;
610 }
611 
613  ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts)
614 {
615  /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
616  ImageUser save_iuser;
617  if (iuser == nullptr) {
618  BKE_imageuser_default(&save_iuser);
619  iuser = &save_iuser;
620  iuser->scene = opts->scene;
621  }
622 
623  bool colorspace_changed = false;
624 
625  eUDIM_TILE_FORMAT tile_format;
626  char *udim_pattern = nullptr;
627 
628  if (ima->source == IMA_SRC_TILED) {
629  /* Verify filepath for tiled images contains a valid UDIM marker. */
630  udim_pattern = BKE_image_get_tile_strformat(opts->filepath, &tile_format);
631  if (tile_format == UDIM_TILE_FORMAT_NONE) {
632  BKE_reportf(reports,
633  RPT_ERROR,
634  "When saving a tiled image, the path '%s' must contain a valid UDIM marker",
635  opts->filepath);
636  return false;
637  }
638  }
639 
640  /* Save images */
641  bool ok = false;
642  if (ima->source != IMA_SRC_TILED) {
643  ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
644  }
645  else {
646  /* Save all the tiles. */
647  LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
648  ImageSaveOptions tile_opts = *opts;
650  tile_opts.filepath, udim_pattern, tile_format, tile->tile_number);
651 
652  iuser->tile = tile->tile_number;
653  ok = image_save_single(reports, ima, iuser, &tile_opts, &colorspace_changed);
654  if (!ok) {
655  break;
656  }
657  }
658 
659  /* Set the image path only if all tiles were ok. */
660  if (ok) {
661  image_save_update_filepath(ima, opts->filepath, opts);
662  }
663  MEM_freeN(udim_pattern);
664  }
665 
666  if (colorspace_changed) {
667  BKE_image_signal(bmain, ima, nullptr, IMA_SIGNAL_COLORMANAGE);
668  }
669 
670  return ok;
671 }
672 
673 /* OpenEXR saving, single and multilayer. */
674 
675 static float *image_exr_from_scene_linear_to_output(float *rect,
676  const int width,
677  const int height,
678  const int channels,
679  const ImageFormatData *imf,
680  Vector<float *> &tmp_output_rects)
681 {
682  if (imf == nullptr) {
683  return rect;
684  }
685 
686  const char *to_colorspace = imf->linear_colorspace_settings.name;
687  if (to_colorspace[0] == '\0' || IMB_colormanagement_space_name_is_scene_linear(to_colorspace)) {
688  return rect;
689  }
690 
691  float *output_rect = (float *)MEM_dupallocN(rect);
692  tmp_output_rects.append(output_rect);
693 
694  const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(
697  output_rect, width, height, channels, from_colorspace, to_colorspace, false);
698 
699  return output_rect;
700 }
701 
703  const RenderResult *rr,
704  const char *filepath,
705  const ImageFormatData *imf,
706  const bool save_as_render,
707  const char *view,
708  int layer)
709 {
710  void *exrhandle = IMB_exr_get_handle();
711  const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16);
712  const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR);
713  const bool write_z = !multi_layer && (imf && (imf->flag & R_IMF_FLAG_ZBUF));
714  Vector<float *> tmp_output_rects;
715 
716  /* Write first layer if not multilayer and no layer was specified. */
717  if (!multi_layer && layer == -1) {
718  layer = 0;
719  }
720 
721  /* First add views since IMB_exr_add_channel checks number of views. */
722  const RenderView *first_rview = (const RenderView *)rr->views.first;
723  if (first_rview && (first_rview->next || first_rview->name[0])) {
724  LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
725  if (!view || STREQ(view, rview->name)) {
726  IMB_exr_add_view(exrhandle, rview->name);
727  }
728  }
729  }
730 
731  /* Compositing result. */
732  if (rr->have_combined) {
733  LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
734  if (!rview->rectf) {
735  continue;
736  }
737 
738  const char *viewname = rview->name;
739  if (view) {
740  if (!STREQ(view, viewname)) {
741  continue;
742  }
743 
744  viewname = "";
745  }
746 
747  /* Skip compositing if only a single other layer is requested. */
748  if (!multi_layer && layer != 0) {
749  continue;
750  }
751 
752  float *output_rect = (save_as_render) ?
754  rview->rectf, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
755  rview->rectf;
756 
757  for (int a = 0; a < 4; a++) {
758  char passname[EXR_PASS_MAXNAME];
759  char layname[EXR_PASS_MAXNAME];
760  const char *chan_id = "RGBA";
761 
762  if (multi_layer) {
763  RE_render_result_full_channel_name(passname, nullptr, "Combined", nullptr, chan_id, a);
764  BLI_strncpy(layname, "Composite", sizeof(layname));
765  }
766  else {
767  passname[0] = chan_id[a];
768  passname[1] = '\0';
769  layname[0] = '\0';
770  }
771 
773  exrhandle, layname, passname, viewname, 4, 4 * rr->rectx, output_rect + a, half_float);
774  }
775 
776  if (write_z && rview->rectz) {
777  const char *layname = (multi_layer) ? "Composite" : "";
778  IMB_exr_add_channel(exrhandle, layname, "Z", viewname, 1, rr->rectx, rview->rectz, false);
779  }
780  }
781  }
782 
783  /* Other render layers. */
784  int nr = (rr->have_combined) ? 1 : 0;
785  LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
786  /* Skip other render layers if requested. */
787  if (!multi_layer && nr != layer) {
788  nr++;
789  continue;
790  }
791  nr++;
792 
793  LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
794  /* Skip non-RGBA and Z passes if not using multi layer. */
795  if (!multi_layer && !(STREQ(rp->name, RE_PASSNAME_COMBINED) || STREQ(rp->name, "") ||
796  (STREQ(rp->name, RE_PASSNAME_Z) && write_z))) {
797  continue;
798  }
799 
800  /* Skip pass if it does not match the requested view(s). */
801  const char *viewname = rp->view;
802  if (view) {
803  if (!STREQ(view, viewname)) {
804  continue;
805  }
806 
807  viewname = "";
808  }
809 
810  /* We only store RGBA passes as half float, for
811  * others precision loss can be problematic. */
812  const bool pass_RGBA = (STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A"));
813  const bool pass_half_float = half_float && pass_RGBA;
814 
815  /* Color-space conversion only happens on RGBA passes. */
816  float *output_rect =
817  (save_as_render && pass_RGBA) ?
819  rp->rect, rr->rectx, rr->recty, rp->channels, imf, tmp_output_rects) :
820  rp->rect;
821 
822  for (int a = 0; a < rp->channels; a++) {
823  /* Save Combined as RGBA if single layer save. */
824  char passname[EXR_PASS_MAXNAME];
825  char layname[EXR_PASS_MAXNAME];
826 
827  if (multi_layer) {
828  RE_render_result_full_channel_name(passname, nullptr, rp->name, nullptr, rp->chan_id, a);
829  BLI_strncpy(layname, rl->name, sizeof(layname));
830  }
831  else {
832  passname[0] = rp->chan_id[a];
833  passname[1] = '\0';
834  layname[0] = '\0';
835  }
836 
837  IMB_exr_add_channel(exrhandle,
838  layname,
839  passname,
840  viewname,
841  rp->channels,
842  rp->channels * rr->rectx,
843  output_rect + a,
844  pass_half_float);
845  }
846  }
847  }
848 
849  errno = 0;
850 
851  BLI_make_existing_file(filepath);
852 
853  int compress = (imf ? imf->exr_codec : 0);
854  bool success = IMB_exr_begin_write(
855  exrhandle, filepath, rr->rectx, rr->recty, compress, rr->stamp_data);
856  if (success) {
857  IMB_exr_write_channels(exrhandle);
858  }
859  else {
860  /* TODO: get the error from openexr's exception. */
861  BKE_reportf(
862  reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno));
863  }
864 
865  for (float *rect : tmp_output_rects) {
866  MEM_freeN(rect);
867  }
868 
869  IMB_exr_close(exrhandle);
870  return success;
871 }
872 
873 /* Render output. */
874 
875 static void image_render_print_save_message(ReportList *reports, const char *name, int ok, int err)
876 {
877  if (ok) {
878  /* no need to report, just some helpful console info */
879  printf("Saved: '%s'\n", name);
880  }
881  else {
882  /* report on error since users will want to know what failed */
883  BKE_reportf(reports, RPT_ERROR, "Render error (%s) cannot save: '%s'", strerror(err), name);
884  }
885 }
886 
888  const Scene *scene,
889  const RenderResult *rr,
890  ImBuf *ibuf,
891  const char *name,
892  const ImageFormatData *imf,
893  const bool stamp)
894 {
895  int ok;
896 
897  if (stamp) {
898  /* writes the name of the individual cameras */
899  ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, imf);
900  }
901  else {
902  ok = BKE_imbuf_write(ibuf, name, imf);
903  }
904 
905  image_render_print_save_message(reports, name, ok, errno);
906 
907  return ok;
908 }
909 
911  RenderResult *rr,
912  const Scene *scene,
913  const bool stamp,
914  const char *filepath_basis)
915 {
916  bool ok = true;
917 
918  if (!rr) {
919  return false;
920  }
921 
922  ImageFormatData image_format;
923  BKE_image_format_init_for_write(&image_format, scene, nullptr);
924 
925  const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
926  const bool is_exr_rr = ELEM(
928  RE_HasFloatPixels(rr);
929  const float dither = scene->r.dither_intensity;
930 
931  if (image_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
932  ok = BKE_image_render_write_exr(reports, rr, filepath_basis, &image_format, true, nullptr, -1);
933  image_render_print_save_message(reports, filepath_basis, ok, errno);
934  }
935 
936  /* mono, legacy code */
937  else if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
938  int view_id = 0;
939  for (const RenderView *rv = (const RenderView *)rr->views.first; rv;
940  rv = rv->next, view_id++) {
941  char filepath[FILE_MAX];
942  if (is_mono) {
943  STRNCPY(filepath, filepath_basis);
944  }
945  else {
946  BKE_scene_multiview_view_filepath_get(&scene->r, filepath_basis, rv->name, filepath);
947  }
948 
949  if (is_exr_rr) {
950  ok = BKE_image_render_write_exr(reports, rr, filepath, &image_format, true, rv->name, -1);
951  image_render_print_save_message(reports, filepath, ok, errno);
952 
953  /* optional preview images for exr */
954  if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
955  image_format.imtype = R_IMF_IMTYPE_JPEG90;
956  image_format.depth = R_IMF_CHAN_DEPTH_8;
957 
958  if (BLI_path_extension_check(filepath, ".exr")) {
959  filepath[strlen(filepath) - 4] = 0;
960  }
961  BKE_image_path_ensure_ext_from_imformat(filepath, &image_format);
962 
963  ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
964  ibuf->planes = 24;
965  IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
966 
968  reports, scene, rr, ibuf, filepath, &image_format, stamp);
969 
970  IMB_freeImBuf(ibuf);
971  }
972  }
973  else {
974  ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
975 
976  IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
977 
979  reports, scene, rr, ibuf, filepath, &image_format, stamp);
980 
981  /* imbuf knows which rects are not part of ibuf */
982  IMB_freeImBuf(ibuf);
983  }
984  }
985  }
986  else { /* R_IMF_VIEWS_STEREO_3D */
988 
989  char filepath[FILE_MAX];
990  STRNCPY(filepath, filepath_basis);
991 
992  if (image_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
993  printf("Stereo 3D not supported for MultiLayer image: %s\n", filepath);
994  }
995  else {
996  ImBuf *ibuf_arr[3] = {nullptr};
997  const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
998  int i;
999 
1000  for (i = 0; i < 2; i++) {
1001  int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
1002  ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
1003  IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format);
1004  }
1005 
1006  ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]);
1007 
1009  reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
1010 
1011  /* optional preview images for exr */
1012  if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
1013  image_format.imtype = R_IMF_IMTYPE_JPEG90;
1014  image_format.depth = R_IMF_CHAN_DEPTH_8;
1015 
1016  if (BLI_path_extension_check(filepath, ".exr")) {
1017  filepath[strlen(filepath) - 4] = 0;
1018  }
1019 
1020  BKE_image_path_ensure_ext_from_imformat(filepath, &image_format);
1021  ibuf_arr[2]->planes = 24;
1022 
1024  reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
1025  }
1026 
1027  /* imbuf knows which rects are not part of ibuf */
1028  for (i = 0; i < 3; i++) {
1029  IMB_freeImBuf(ibuf_arr[i]);
1030  }
1031  }
1032  }
1033 
1034  BKE_image_format_free(&image_format);
1035 
1036  return ok;
1037 }
bool BKE_color_managed_colorspace_settings_equals(const struct ColorManagedColorspaceSettings *settings1, const struct ColorManagedColorspaceSettings *settings2)
void BKE_color_managed_colorspace_settings_copy(struct ColorManagedColorspaceSettings *colorspace_settings, const struct ColorManagedColorspaceSettings *settings)
eUDIM_TILE_FORMAT
Definition: BKE_image.h:378
@ UDIM_TILE_FORMAT_NONE
Definition: BKE_image.h:379
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock)
int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, const struct ImageFormatData *imf, bool save_copy)
struct RenderResult * BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima)
void BKE_image_set_filepath_from_tile_number(char *filepath, const char *pattern, eUDIM_TILE_FORMAT tile_format, int tile_number)
bool BKE_imbuf_alpha_test(struct ImBuf *ibuf)
int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, const struct ImageFormatData *imf)
struct ImBuf * BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock)
bool BKE_image_is_multiview(const struct Image *ima)
void BKE_imbuf_stamp_info(const struct RenderResult *rr, struct ImBuf *ibuf)
struct RenderPass * BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser)
bool BKE_image_is_stereo(const struct Image *ima)
#define IMA_SIGNAL_COLORMANAGE
Definition: BKE_image.h:135
void BKE_image_multiview_index(const struct Image *ima, struct ImageUser *iuser)
void BKE_image_user_file_path_ex(const struct Main *bmain, const struct ImageUser *iuser, const struct Image *ima, char *path, const bool resolve_udim, const bool resolve_multiview)
int BKE_imbuf_write_stamp(const struct Scene *scene, const struct RenderResult *rr, struct ImBuf *ibuf, const char *name, const struct ImageFormatData *imf)
void BKE_image_signal(struct Main *bmain, struct Image *ima, struct ImageUser *iuser, int signal)
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima)
char * BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format)
void BKE_imageuser_default(struct ImageUser *iuser)
void BKE_image_format_free(struct ImageFormatData *imf)
Definition: image_format.cc:52
void BKE_image_format_from_imbuf(struct ImageFormatData *im_format, const struct ImBuf *imbuf)
void BKE_image_format_to_imbuf(struct ImBuf *ibuf, const struct ImageFormatData *imf)
int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format)
void BKE_image_format_init(struct ImageFormatData *imf, const bool render)
Definition: image_format.cc:26
char BKE_imtype_valid_depths(char imtype)
void BKE_image_format_color_management_copy_from_scene(struct ImageFormatData *imf, const struct Scene *scene)
void BKE_image_format_init_for_write(struct ImageFormatData *imf, const struct Scene *scene_src, const struct ImageFormatData *imf_src)
bool BKE_imtype_requires_linear_float(char imtype)
const char * BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL()
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.c:83
void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd, const char *filepath, const char *view, char *r_filepath)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
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)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findstring(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_make_safe(char *path) ATTR_NONNULL(1)
Definition: path_util.c:314
bool BLI_make_existing_file(const char *name)
Definition: path_util.c:1197
#define FILE_MAX
bool BLI_path_extension_check(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1299
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL()
Definition: path_util.c:450
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL()
Definition: path_util.c:897
#define STR_ELEM(...)
Definition: BLI_string.h:539
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define STR_CONCAT(dst, len, suffix)
Definition: BLI_string.h:488
#define ELEM(...)
#define STREQ(a, b)
#define ID_BLEND_PATH(_bmain, _id)
Definition: DNA_ID.h:559
@ IMA_SRC_FILE
@ IMA_SRC_GENERATED
@ IMA_SRC_VIEWER
@ IMA_SRC_TILED
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ IMA_TYPE_IMAGE
#define IMA_SHOW_STEREO
#define RE_PASSNAME_COMBINED
#define STEREO_LEFT_NAME
#define R_IMF_PLANES_BW
#define R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE
#define R_IMF_IMTYPE_MULTILAYER
@ 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 R_IMF_PLANES_RGBA
#define RE_PASSNAME_Z
#define STEREO_RIGHT_NAME
#define R_IMF_FLAG_PREVIEW_JPG
@ R_IMF_VIEWS_MULTIVIEW
@ R_IMF_VIEWS_STEREO_3D
@ R_IMF_VIEWS_INDIVIDUAL
#define R_IMF_FLAG_ZBUF
#define R_IMF_IMTYPE_OPENEXR
#define R_IMF_PLANES_RGB
#define R_IMF_IMTYPE_JPEG90
static AppView * view
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
struct ImBuf * IMB_colormanagement_imbuf_for_write(struct ImBuf *ibuf, bool save_as_render, bool allocate_result, const struct ImageFormatData *image_format)
bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
@ COLOR_ROLE_DEFAULT_FLOAT
@ COLOR_ROLE_DEFAULT_BYTE
@ COLOR_ROLE_SCENE_LINEAR
bool IMB_colormanagement_space_name_is_data(const char *name)
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_freerectfloatImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:80
void IMB_freezbuffloatImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:168
struct ImBuf * IMB_stereo3d_ImBuf(const struct ImageFormatData *im_format, struct ImBuf *ibuf_left, struct ImBuf *ibuf_right)
struct ImBuf * IMB_dupImBuf(const struct ImBuf *ibuf1)
void imb_freerectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:97
void IMB_freezbufImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:154
Contains defines and structs used throughout the imbuf module.
@ IB_BITMAPDIRTY
@ IB_zbuf
@ IB_rectfloat
@ IB_zbuffloat
@ IB_rect
bool IMB_exr_begin_write(void *handle, const char *filepath, int width, int height, int compress, const struct StampData *stamp)
void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, const char *view, int xstride, int ystride, float *rect, bool use_half_float)
void IMB_exr_add_view(void *handle, const char *name)
void IMB_exr_close(void *handle)
#define EXR_PASS_MAXNAME
Definition: IMB_openexr.h:15
void IMB_exr_write_channels(void *handle)
void * IMB_exr_get_handle(void)
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 Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input 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 a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
volatile int lock
ColorManagedColorspaceSettings colorspace_settings
char views_format
char filepath[1024]
ListBase tiles
short type
short source
ListBase views
struct Stereo3dFormat * stereo3d_format
void append(const T &value)
Definition: BLI_vector.hh:433
Scene scene
int len
Definition: draw_manager.c:108
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
bool BKE_image_save(ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts)
Definition: image_save.cc:612
bool BKE_image_render_write(ReportList *reports, RenderResult *rr, const Scene *scene, const bool stamp, const char *filepath_basis)
Definition: image_save.cc:910
static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
Definition: image_save.cc:329
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)
Definition: image_save.cc:702
static char imtype_best_depth(ImBuf *ibuf, const char imtype)
Definition: image_save.cc:38
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:76
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)
Definition: image_save.cc:675
static void image_save_post(ReportList *reports, Image *ima, ImBuf *ibuf, int ok, const ImageSaveOptions *opts, int save_copy, const char *filepath, bool *r_colorspace_changed)
Definition: image_save.cc:261
static bool image_save_single(ReportList *reports, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts, bool *r_colorspace_changed)
Definition: image_save.cc:349
static void image_save_update_filepath(Image *ima, const char *filepath, const ImageSaveOptions *opts)
Definition: image_save.cc:246
static void image_render_print_save_message(ReportList *reports, const char *name, int ok, int err)
Definition: image_save.cc:875
void BKE_image_save_options_update(ImageSaveOptions *opts, const Image *image)
Definition: image_save.cc:197
static int image_render_write_stamp_test(ReportList *reports, const Scene *scene, const RenderResult *rr, ImBuf *ibuf, const char *name, const ImageFormatData *imf, const bool stamp)
Definition: image_save.cc:887
void BKE_image_save_options_free(ImageSaveOptions *opts)
Definition: image_save.cc:241
ccl_global const KernelWorkTile * tile
static char ** names
Definition: makesdna.c:65
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
#define G(x, y, z)
static unsigned a[3]
Definition: RandGen.cpp:78
bool RE_HasFloatPixels(const RenderResult *rr)
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)
char name[66]
Definition: DNA_ID.h:378
float * zbuf_float
int userflags
ImbFormatOptions foptions
unsigned char planes
char name[IMB_FILENAME_SIZE]
enum eImbFileType ftype
unsigned int * rect
float * rect_float
int * zbuf
ColorManagedColorspaceSettings linear_colorspace_settings
Stereo3dFormat stereo3d_format
struct ImageFormatData im_format
struct Scene * scene
struct Main * bmain
char filepath[1024]
struct Scene * scene
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
struct ImageFormatData im_format
float dither_intensity
ListBase views
Definition: RE_pipeline.h:125
ListBase layers
Definition: RE_pipeline.h:122
struct StampData * stamp_data
Definition: RE_pipeline.h:141
struct RenderView * next
Definition: RE_pipeline.h:50
char name[64]
Definition: RE_pipeline.h:51
struct RenderData r
static FT_Error err