Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/image_save.c
| Show First 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene) | ||||
| opts->bmain = bmain; | opts->bmain = bmain; | ||||
| opts->scene = scene; | opts->scene = scene; | ||||
| BKE_imformat_defaults(&opts->im_format); | BKE_imformat_defaults(&opts->im_format); | ||||
| } | } | ||||
| static void image_save_post(ReportList *reports, | static void image_save_post(ReportList *reports, | ||||
| Main *bmain, | |||||
| Image *ima, | Image *ima, | ||||
| ImBuf *ibuf, | ImBuf *ibuf, | ||||
| int ok, | int ok, | ||||
| ImageSaveOptions *opts, | ImageSaveOptions *opts, | ||||
| int save_copy, | int save_copy, | ||||
| const char *filepath) | const char *filepath, | ||||
| bool *r_colorspace_changed) | |||||
| { | { | ||||
| if (!ok) { | if (!ok) { | ||||
| BKE_reportf(reports, RPT_ERROR, "Could not write image: %s", strerror(errno)); | BKE_reportf(reports, RPT_ERROR, "Could not write image: %s", strerror(errno)); | ||||
| return; | return; | ||||
| } | } | ||||
| if (save_copy) { | if (save_copy) { | ||||
| return; | return; | ||||
| Show All 37 Lines | if (opts->relative) { | ||||
| BLI_path_rel(ima->name, relbase); /* only after saving */ | BLI_path_rel(ima->name, relbase); /* only after saving */ | ||||
| } | } | ||||
| ColorManagedColorspaceSettings old_colorspace_settings; | ColorManagedColorspaceSettings old_colorspace_settings; | ||||
| BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings, &ima->colorspace_settings); | BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings, &ima->colorspace_settings); | ||||
| IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf); | IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf); | ||||
| if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings, | if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings, | ||||
| &ima->colorspace_settings)) { | &ima->colorspace_settings)) { | ||||
| BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE); | *r_colorspace_changed = true; | ||||
| } | } | ||||
| } | } | ||||
| static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf) | static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf) | ||||
| { | { | ||||
| if (colormanaged_ibuf != ibuf) { | if (colormanaged_ibuf != ibuf) { | ||||
| /* This guys might be modified by image buffer write functions, | /* This guys might be modified by image buffer write functions, | ||||
| * need to copy them back from color managed image buffer to an | * need to copy them back from color managed image buffer to an | ||||
| * original one, so file type of image is being properly updated. | * original one, so file type of image is being properly updated. | ||||
| */ | */ | ||||
| ibuf->ftype = colormanaged_ibuf->ftype; | ibuf->ftype = colormanaged_ibuf->ftype; | ||||
| ibuf->foptions = colormanaged_ibuf->foptions; | ibuf->foptions = colormanaged_ibuf->foptions; | ||||
| ibuf->planes = colormanaged_ibuf->planes; | ibuf->planes = colormanaged_ibuf->planes; | ||||
| IMB_freeImBuf(colormanaged_ibuf); | IMB_freeImBuf(colormanaged_ibuf); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * \return success. | * \return success. | ||||
| * \note ``ima->name`` and ``ibuf->name`` should end up the same. | * \note ``ima->name`` and ``ibuf->name`` should end up the same. | ||||
| * \note for multiview the first ``ibuf`` is important to get the settings. | * \note for multiview the first ``ibuf`` is important to get the settings. | ||||
| */ | */ | ||||
| static bool image_save_single( | static bool image_save_single(ReportList *reports, | ||||
| ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts) | Image *ima, | ||||
| ImageUser *iuser, | |||||
| ImageSaveOptions *opts, | |||||
| bool *r_colorspace_changed) | |||||
| { | { | ||||
| void *lock; | void *lock; | ||||
| ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); | ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); | ||||
| RenderResult *rr = NULL; | RenderResult *rr = NULL; | ||||
| bool ok = false; | bool ok = false; | ||||
| if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) { | if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) { | ||||
| BKE_image_release_ibuf(ima, ibuf, lock); | BKE_image_release_ibuf(ima, ibuf, lock); | ||||
| ▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | if (imf->views_format == R_IMF_VIEWS_STEREO_3D) { | ||||
| } | } | ||||
| } | } | ||||
| BKE_imbuf_stamp_info(rr, ibuf); | BKE_imbuf_stamp_info(rr, ibuf); | ||||
| } | } | ||||
| /* fancy multiview OpenEXR */ | /* fancy multiview OpenEXR */ | ||||
| if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { | if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) { | ||||
| /* save render result */ | /* save render result */ | ||||
| ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer); | ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer); | ||||
| image_save_post(reports, bmain, ima, ibuf, ok, opts, true, opts->filepath); | image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed); | ||||
| BKE_image_release_ibuf(ima, ibuf, lock); | BKE_image_release_ibuf(ima, ibuf, lock); | ||||
| } | } | ||||
| /* regular mono pipeline */ | /* regular mono pipeline */ | ||||
| else if (is_mono) { | else if (is_mono) { | ||||
| if (is_exr_rr) { | if (is_exr_rr) { | ||||
brecht: It's not ideal to make assumptions about the calling function saving all UDIM tiles.
Instead I… | |||||
| ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer); | ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer); | ||||
| } | } | ||||
| else { | else { | ||||
| colormanaged_ibuf = IMB_colormanagement_imbuf_for_write( | colormanaged_ibuf = IMB_colormanagement_imbuf_for_write( | ||||
| ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); | ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); | ||||
| ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy); | ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy); | ||||
| imbuf_save_post(ibuf, colormanaged_ibuf); | imbuf_save_post(ibuf, colormanaged_ibuf); | ||||
| } | } | ||||
| image_save_post( | image_save_post(reports, | ||||
| reports, bmain, ima, ibuf, ok, opts, (is_exr_rr ? true : save_copy), opts->filepath); | ima, | ||||
| ibuf, | |||||
| ok, | |||||
| opts, | |||||
| (is_exr_rr ? true : save_copy), | |||||
| opts->filepath, | |||||
| r_colorspace_changed); | |||||
| BKE_image_release_ibuf(ima, ibuf, lock); | BKE_image_release_ibuf(ima, ibuf, lock); | ||||
| } | } | ||||
| /* individual multiview images */ | /* individual multiview images */ | ||||
| else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) { | else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) { | ||||
| int i; | int i; | ||||
| unsigned char planes = ibuf->planes; | unsigned char planes = ibuf->planes; | ||||
| const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views)); | const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views)); | ||||
| if (!is_exr_rr) { | if (!is_exr_rr) { | ||||
| BKE_image_release_ibuf(ima, ibuf, lock); | BKE_image_release_ibuf(ima, ibuf, lock); | ||||
| } | } | ||||
| for (i = 0; i < totviews; i++) { | for (i = 0; i < totviews; i++) { | ||||
| char filepath[FILE_MAX]; | char filepath[FILE_MAX]; | ||||
| bool ok_view = false; | bool ok_view = false; | ||||
| const char *view = rr ? ((RenderView *)BLI_findlink(&rr->views, i))->name : | const char *view = rr ? ((RenderView *)BLI_findlink(&rr->views, i))->name : | ||||
| ((ImageView *)BLI_findlink(&ima->views, i))->name; | ((ImageView *)BLI_findlink(&ima->views, i))->name; | ||||
| if (is_exr_rr) { | if (is_exr_rr) { | ||||
| BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath); | BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath); | ||||
| ok_view = RE_WriteRenderResult(reports, rr, filepath, imf, view, layer); | ok_view = RE_WriteRenderResult(reports, rr, filepath, imf, view, layer); | ||||
| image_save_post(reports, bmain, ima, ibuf, ok_view, opts, true, filepath); | image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed); | ||||
| } | } | ||||
| else { | else { | ||||
| /* copy iuser to get the correct ibuf for this view */ | /* copy iuser to get the correct ibuf for this view */ | ||||
| ImageUser view_iuser; | ImageUser view_iuser; | ||||
| if (iuser) { | if (iuser) { | ||||
| /* copy iuser to get the correct ibuf for this view */ | /* copy iuser to get the correct ibuf for this view */ | ||||
| view_iuser = *iuser; | view_iuser = *iuser; | ||||
| Show All 16 Lines | for (i = 0; i < totviews; i++) { | ||||
| ibuf->planes = planes; | ibuf->planes = planes; | ||||
| BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath); | BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath); | ||||
| colormanaged_ibuf = IMB_colormanagement_imbuf_for_write( | colormanaged_ibuf = IMB_colormanagement_imbuf_for_write( | ||||
| ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); | ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); | ||||
| ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy); | ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy); | ||||
| imbuf_save_post(ibuf, colormanaged_ibuf); | imbuf_save_post(ibuf, colormanaged_ibuf); | ||||
| image_save_post(reports, bmain, ima, ibuf, ok_view, opts, true, filepath); | image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed); | ||||
| BKE_image_release_ibuf(ima, ibuf, lock); | BKE_image_release_ibuf(ima, ibuf, lock); | ||||
| } | } | ||||
| ok &= ok_view; | ok &= ok_view; | ||||
| } | } | ||||
| if (is_exr_rr) { | if (is_exr_rr) { | ||||
| BKE_image_release_ibuf(ima, ibuf, lock); | BKE_image_release_ibuf(ima, ibuf, lock); | ||||
| } | } | ||||
| } | } | ||||
| /* stereo (multiview) images */ | /* stereo (multiview) images */ | ||||
| else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) { | else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) { | ||||
| if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) { | if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) { | ||||
| ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer); | ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer); | ||||
| image_save_post(reports, bmain, ima, ibuf, ok, opts, true, opts->filepath); | image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed); | ||||
| BKE_image_release_ibuf(ima, ibuf, lock); | BKE_image_release_ibuf(ima, ibuf, lock); | ||||
| } | } | ||||
| else { | else { | ||||
| ImBuf *ibuf_stereo[2] = {NULL}; | ImBuf *ibuf_stereo[2] = {NULL}; | ||||
| unsigned char planes = ibuf->planes; | unsigned char planes = ibuf->planes; | ||||
| const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; | const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; | ||||
| int i; | int i; | ||||
| ▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| bool BKE_image_save( | bool BKE_image_save( | ||||
| ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts) | ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts) | ||||
| { | { | ||||
| ImageUser save_iuser; | ImageUser save_iuser; | ||||
| BKE_imageuser_default(&save_iuser); | BKE_imageuser_default(&save_iuser); | ||||
| bool colorspace_changed = false; | |||||
| if (ima->source == IMA_SRC_TILED) { | if (ima->source == IMA_SRC_TILED) { | ||||
| /* Verify filepath for tiles images. */ | /* Verify filepath for tiles images. */ | ||||
| if (BLI_stringdec(opts->filepath, NULL, NULL, NULL) != 1001) { | if (BLI_stringdec(opts->filepath, NULL, NULL, NULL) != 1001) { | ||||
| BKE_reportf(reports, | BKE_reportf(reports, | ||||
| RPT_ERROR, | RPT_ERROR, | ||||
| "When saving a tiled image, the path '%s' must contain the UDIM tag 1001", | "When saving a tiled image, the path '%s' must contain the UDIM tag 1001", | ||||
| opts->filepath); | opts->filepath); | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */ | /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */ | ||||
| if (iuser == NULL) { | if (iuser == NULL) { | ||||
| iuser = &save_iuser; | iuser = &save_iuser; | ||||
| } | } | ||||
| } | } | ||||
| /* Save image - or, for tiled images, the first tile. */ | /* Save image - or, for tiled images, the first tile. */ | ||||
| bool ok = image_save_single(reports, bmain, ima, iuser, opts); | bool ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed); | ||||
| if (ok && ima->source == IMA_SRC_TILED) { | if (ok && ima->source == IMA_SRC_TILED) { | ||||
| char filepath[FILE_MAX]; | char filepath[FILE_MAX]; | ||||
| BLI_strncpy(filepath, opts->filepath, sizeof(filepath)); | BLI_strncpy(filepath, opts->filepath, sizeof(filepath)); | ||||
| char head[FILE_MAX], tail[FILE_MAX]; | char head[FILE_MAX], tail[FILE_MAX]; | ||||
| unsigned short numlen; | unsigned short numlen; | ||||
| BLI_stringdec(filepath, head, tail, &numlen); | BLI_stringdec(filepath, head, tail, &numlen); | ||||
| /* Save all other tiles. */ | /* Save all other tiles. */ | ||||
| LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { | LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { | ||||
| /* Tile 1001 was already saved before the loop. */ | /* Tile 1001 was already saved before the loop. */ | ||||
| if (tile->tile_number == 1001 || !ok) { | if (tile->tile_number == 1001 || !ok) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Build filepath of the tile. */ | /* Build filepath of the tile. */ | ||||
| BLI_stringenc(opts->filepath, head, tail, numlen, tile->tile_number); | BLI_stringenc(opts->filepath, head, tail, numlen, tile->tile_number); | ||||
| iuser->tile = tile->tile_number; | iuser->tile = tile->tile_number; | ||||
| ok = ok && image_save_single(reports, bmain, ima, iuser, opts); | ok = ok && image_save_single(reports, ima, iuser, opts, &colorspace_changed); | ||||
| } | } | ||||
| BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath)); | BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath)); | ||||
| } | } | ||||
| if (colorspace_changed) { | |||||
| BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE); | |||||
| } | |||||
| return ok; | return ok; | ||||
| } | } | ||||
It's not ideal to make assumptions about the calling function saving all UDIM tiles.
Instead I would add a bool *colorspace_changed parameter to image_save_single and image_save_post, which can then be used by BKE_image_save to determine if it should call BKE_image_signal.