56 const bool guess_path,
57 const bool save_as_render)
61 if (iuser ==
nullptr) {
142 if (guess_path && opts->
filepath[0] == 0) {
143 const bool is_prev_save = !
STREQ(
G.filepath_last_image,
"//");
174 return (ibuf !=
nullptr);
211 const char *filepath,
230 const bool save_copy,
231 const char *filepath,
232 bool *r_colorspace_changed)
237 "Could not write image: %s",
238 errno ? strerror(errno) :
"internal error, see console");
284 *r_colorspace_changed =
true;
303 *r_colorspace_changed =
true;
309 if (colormanaged_ibuf != ibuf) {
332 bool *r_colorspace_changed)
345 ImBuf *colormanaged_ibuf =
nullptr;
376 const int layer = (iuser && !is_multilayer) ? iuser->
layer : -1;
392 R
"(Did not write, the image doesn't have a "%s" and "%s" views)",
406 R
"(Did not write, the image doesn't have a "%s" and "%s" views)",
418 double rr_ppm_prev[2] = {0, 0};
420 if (save_as_render && rr) {
424 double ppm[2] = {0, 0};
433 auto render_result_restore_ppm = [rr, save_as_render, rr_ppm_prev]() {
434 if (save_as_render && rr) {
443 reports, rr, opts->
filepath, imf, save_as_render,
nullptr, layer);
445 render_result_restore_ppm();
454 reports, rr, opts->
filepath, imf, save_as_render,
nullptr, layer);
462 render_result_restore_ppm();
469 (is_exr_rr ?
true : save_copy),
471 r_colorspace_changed);
483 for (
int i = 0;
i < totviews;
i++) {
485 bool ok_view =
false;
492 reports, rr, filepath, imf, save_as_render,
view, layer);
493 image_save_post(reports, ima, ibuf, ok_view, opts,
true, filepath, r_colorspace_changed);
525 image_save_post(reports, ima, ibuf, ok_view, opts,
true, filepath, r_colorspace_changed);
531 render_result_restore_ppm();
542 reports, rr, opts->
filepath, imf, save_as_render,
nullptr, layer);
544 render_result_restore_ppm();
550 ImBuf *ibuf_stereo[2] = {
nullptr};
557 bool stereo_ok =
true;
559 for (
int i = 0;
i < 2;
i++) {
573 view_iuser.
view = id;
583 if (ibuf ==
nullptr) {
585 reports,
RPT_ERROR,
"Did not write, unexpected error when saving stereo image");
617 for (
int i = 0;
i < 2;
i++) {
621 render_result_restore_ppm();
626 render_result_restore_ppm();
639 if (iuser ==
nullptr) {
645 bool colorspace_changed =
false;
648 char *udim_pattern =
nullptr;
656 "When saving a tiled image, the path '%s' must contain a valid UDIM marker",
672 tile_opts.
filepath, udim_pattern, tile_format,
tile->tile_number);
691 if (colorspace_changed) {
709 if (imf ==
nullptr) {
719 tmp_output_rects.
append(output_rect);
724 output_rect, width, height, channels, from_colorspace, to_colorspace,
false);
726 r_colorspace = to_colorspace;
732 float *input_buffer,
int width,
int height,
int channels,
Vector<float *> &temporary_buffers)
735 "Gray Scale Buffer For EXR");
736 temporary_buffers.
append(gray_scale_output);
740 for (
const int64_t y : sub_y_range) {
749 return gray_scale_output;
757 "Opaque Alpha Buffer For EXR");
758 temporary_buffers.
append(alpha_output);
762 for (
const int64_t y : sub_y_range) {
764 alpha_output[
y *
int64_t(width) +
x] = 1.0;
776 const char *view_name,
788 if (!is_multi_layer && layer != 0) {
795 if (!render_view->ibuf || !render_view->ibuf->float_buffer.data) {
801 if (view_name && !
STREQ(view_name, render_view->name)) {
807 const char *render_view_name = view_name ?
"" : render_view->name;
810 const int channels_count_in_buffer = 4;
811 float *output_buffer = render_view->ibuf->float_buffer.data;
815 if (save_as_render) {
817 render_result->
rectx,
818 render_result->
recty,
819 channels_count_in_buffer,
827 if (is_multi_layer) {
829 "Composite.Combined",
833 channels_count_in_buffer,
834 channels_count_in_buffer * render_result->
rectx,
844 const int required_channels = imf ? imf->
planes / 8 : 4;
845 if (required_channels == 1) {
847 render_result->
rectx,
848 render_result->
recty,
849 channels_count_in_buffer,
857 render_result->
rectx,
871 channels_count_in_buffer,
872 channels_count_in_buffer * render_result->
rectx,
880 const char *filepath,
882 const bool save_as_render,
891 if (!multi_layer && layer == -1) {
897 if (first_rview && (first_rview->
next || first_rview->
name[0])) {
913 if (!multi_layer && nr != layer) {
926 const char *viewname = render_pass->view;
939 const bool pass_half_float = half_float && pass_RGBA;
942 float *output_rect = render_pass->ibuf->float_buffer.data;
946 if (save_as_render && pass_RGBA) {
950 render_pass->channels,
958 std::string layer_pass_name = render_pass->name;
961 if (has_multiple_layers || rl->name[0] !=
'\0') {
962 layer_pass_name = rl->name + (
"." + layer_pass_name);
965 std::string channelnames =
blender::StringRef(render_pass->chan_id, render_pass->channels);
971 render_pass->channels,
972 render_pass->channels * rr->
rectx,
984 const int required_channels = imf ? imf->
planes / 8 : 4;
985 if (required_channels == render_pass->channels ||
986 (required_channels != 1 && render_pass->channels != 1))
989 render_pass->chan_id, std::min(required_channels, render_pass->channels));
995 render_pass->channels,
996 render_pass->channels * rr->
rectx,
1000 else if (required_channels == 1) {
1004 output_rect, rr->
rectx, rr->
recty, render_pass->channels, tmp_output_rects);
1015 else if (render_pass->channels == 1) {
1019 for (
int i = 0;
i < 3;
i++) {
1022 std::string(1,
"RGB"[
i]).c_str(),
1034 if (required_channels == 4 && render_pass->channels < 4) {
1038 exrhandle,
"",
"A", viewname, colorspace, 1, rr->
rectx, alpha_output, pass_half_float);
1047 const int compress = (imf ? imf->
exr_codec : 0);
1048 const int quality = (imf ? imf->
quality : 90);
1057 reports,
RPT_ERROR,
"Error writing render result, %s (see console)", strerror(errno));
1060 for (
float *rect : tmp_output_rects) {
1071 const char *filepath,
1082 reports,
RPT_ERROR,
"Render error (%s) cannot save: '%s'", strerror(err), filepath);
1090 const char *filepath,
1113 const char *filepath_basis,
1115 bool save_as_render)
1126 if (!save_as_render) {
1128 &
format->linear_colorspace_settings);
1132 const bool is_exr_rr =
ELEM(
1139 reports, rr, filepath_basis, &image_format, save_as_render,
nullptr, -1);
1150 STRNCPY(filepath, filepath_basis);
1158 reports, rr, filepath, &image_format, save_as_render, rv->name, -1);
1167 filepath[strlen(filepath) - 4] = 0;
1176 reports, scene, rr, ibuf, filepath, &image_format, stamp);
1187 reports, scene, rr, ibuf, filepath, &image_format, stamp);
1198 STRNCPY(filepath, filepath_basis);
1201 printf(
"Stereo 3D not supported for MultiLayer image: %s\n", filepath);
1204 ImBuf *ibuf_arr[3] = {
nullptr};
1208 for (
i = 0;
i < 2;
i++) {
1218 reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
1226 filepath[strlen(filepath) - 4] = 0;
1230 ibuf_arr[2]->
planes = 24;
1233 reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
1242 for (
i = 0;
i < 3;
i++) {
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
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_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
void BKE_image_multiview_index(const Image *ima, ImageUser *iuser)
const char * BKE_main_blendfile_path(const 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)
void BKE_scene_multiview_view_filepath_get(const RenderData *rd, const char *filepath, const char *view, char *r_filepath)
void BKE_scene_ppm_get(const RenderData *rd, double r_ppm[2])
blender::ocio::ColorSpace ColorSpace
File and directory operations.
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count_at_most(const ListBase *listbase, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_findstringindex(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE void copy_v2_v2_db(double r[2], const double a[2])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool bool BLI_path_extension_strip(char *path) ATTR_NONNULL(1)
#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)
bool BLI_path_make_safe_filename(char *filename) ATTR_NONNULL(1)
#define SNPRINTF(dst, format,...)
char * STRNCPY(char(&dst)[N], const char *src)
#define STR_CONCAT(dst, len, suffix)
#define STRNCPY_UTF8(dst, src)
#define CLOG_INFO_NOCHECK(clg_ref, format,...)
#define ID_BLEND_PATH(_bmain, _id)
#define RE_PASSNAME_COMBINED
#define STEREO_RIGHT_NAME
@ R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE
@ R_IMF_EXR_FLAG_MULTIPART
@ R_IMF_IMTYPE_MULTILAYER
bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
void IMB_colormanagement_transform_float(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
@ COLOR_ROLE_DEFAULT_BYTE
@ COLOR_ROLE_SCENE_LINEAR
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)
const char * IMB_colormanagement_colorspace_get_name(const ColorSpace *colorspace)
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
const char * IMB_colormanagement_role_colorspace_name_get(int role)
const ColorSpace * IMB_colormangement_display_get_color_space(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
void IMB_free_float_pixels(ImBuf *ibuf)
void IMB_free_byte_pixels(ImBuf *ibuf)
void IMB_exr_add_channels(ExrHandle *handle, blender::StringRefNull layerpassname, blender::StringRefNull channelnames, blender::StringRefNull viewname, blender::StringRefNull colorspace, size_t xstride, size_t ystride, float *rect, bool use_half_float)
bool IMB_exr_begin_write(ExrHandle *handle, const char *filepath, int width, int height, const double ppm[2], int compress, int quality, const StampData *stamp)
ExrHandle * IMB_exr_get_handle(bool write_multipart=false)
void IMB_exr_close(ExrHandle *handle)
void IMB_exr_write_channels(ExrHandle *handle)
void IMB_exr_add_view(ExrHandle *handle, const char *name)
Read Guarded memory(de)allocation.
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr const char * c_str() const
void append(const T &value)
static void add_exr_compositing_result(ExrHandle *exr_handle, const RenderResult *render_result, const ImageFormatData *imf, bool save_as_render, const char *view_name, int layer, Vector< float * > &temporary_buffers)
bool BKE_image_save(ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts)
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)
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)
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 CLG_LogRef LOG_RENDER
static void image_render_print_save_message(ReportList *reports, const char *filepath, int ok, int err)
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, blender::StringRefNull &r_colorspace)
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)
void BKE_image_save_options_free(ImageSaveOptions *opts)
const ccl_global KernelWorkTile * tile
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_dupallocN(const void *vmemh)
void MEM_freeN(void *vmemh)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
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)
bool RE_ResultIsMultiView(RenderResult *rr)
char filepath[IMB_FILEPATH_SIZE]
ImBufFloatBuffer float_buffer
ImbFormatOptions foptions
ImBufByteBuffer byte_buffer
ImageFormatData im_format
ColorManagedColorspaceSettings colorspace_settings
struct Stereo3dFormat * stereo3d_format
struct ImageFormatData im_format
struct StampData * stamp_data
void * BKE_image_get_tile