1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 */
23
24 #include <errno.h>
25 #include <string.h>
26
27 #include "BLI_listbase.h"
28 #include "BLI_path_util.h"
29 #include "BLI_string.h"
30
31 #include "DNA_image_types.h"
32
33 #include "IMB_colormanagement.h"
34 #include "IMB_imbuf.h"
35 #include "IMB_imbuf_types.h"
36
37 #include "BKE_colortools.h"
38 #include "BKE_image.h"
39 #include "BKE_image_save.h"
40 #include "BKE_main.h"
41 #include "BKE_report.h"
42 #include "BKE_scene.h"
43
44 #include "RE_pipeline.h"
45
BKE_image_save_options_init(ImageSaveOptions * opts,Main * bmain,Scene * scene)46 void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene)
47 {
48 memset(opts, 0, sizeof(*opts));
49
50 opts->bmain = bmain;
51 opts->scene = scene;
52
53 BKE_imformat_defaults(&opts->im_format);
54 }
55
image_save_post(ReportList * reports,Image * ima,ImBuf * ibuf,int ok,ImageSaveOptions * opts,int save_copy,const char * filepath,bool * r_colorspace_changed)56 static void image_save_post(ReportList *reports,
57 Image *ima,
58 ImBuf *ibuf,
59 int ok,
60 ImageSaveOptions *opts,
61 int save_copy,
62 const char *filepath,
63 bool *r_colorspace_changed)
64 {
65 if (!ok) {
66 BKE_reportf(reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
67 return;
68 }
69
70 if (save_copy) {
71 return;
72 }
73
74 if (opts->do_newpath) {
75 BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
76 BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
77 }
78
79 ibuf->userflags &= ~IB_BITMAPDIRTY;
80
81 /* change type? */
82 if (ima->type == IMA_TYPE_R_RESULT) {
83 ima->type = IMA_TYPE_IMAGE;
84
85 /* workaround to ensure the render result buffer is no longer used
86 * by this image, otherwise can crash when a new render result is
87 * created. */
88 if (ibuf->rect && !(ibuf->mall & IB_rect)) {
89 imb_freerectImBuf(ibuf);
90 }
91 if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat)) {
92 imb_freerectfloatImBuf(ibuf);
93 }
94 if (ibuf->zbuf && !(ibuf->mall & IB_zbuf)) {
95 IMB_freezbufImBuf(ibuf);
96 }
97 if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat)) {
98 IMB_freezbuffloatImBuf(ibuf);
99 }
100 }
101 if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
102 ima->source = IMA_SRC_FILE;
103 ima->type = IMA_TYPE_IMAGE;
104 }
105
106 /* only image path, never ibuf */
107 if (opts->relative) {
108 const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
109 BLI_path_rel(ima->filepath, relbase); /* only after saving */
110 }
111
112 ColorManagedColorspaceSettings old_colorspace_settings;
113 BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings, &ima->colorspace_settings);
114 IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
115 if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
116 &ima->colorspace_settings)) {
117 *r_colorspace_changed = true;
118 }
119 }
120
imbuf_save_post(ImBuf * ibuf,ImBuf * colormanaged_ibuf)121 static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
122 {
123 if (colormanaged_ibuf != ibuf) {
124 /* This guys might be modified by image buffer write functions,
125 * need to copy them back from color managed image buffer to an
126 * original one, so file type of image is being properly updated.
127 */
128 ibuf->ftype = colormanaged_ibuf->ftype;
129 ibuf->foptions = colormanaged_ibuf->foptions;
130 ibuf->planes = colormanaged_ibuf->planes;
131
132 IMB_freeImBuf(colormanaged_ibuf);
133 }
134 }
135
136 /**
137 * \return success.
138 * \note ``ima->filepath`` and ``ibuf->name`` should end up the same.
139 * \note for multiview the first ``ibuf`` is important to get the settings.
140 */
image_save_single(ReportList * reports,Image * ima,ImageUser * iuser,ImageSaveOptions * opts,bool * r_colorspace_changed)141 static bool image_save_single(ReportList *reports,
142 Image *ima,
143 ImageUser *iuser,
144 ImageSaveOptions *opts,
145 bool *r_colorspace_changed)
146 {
147 void *lock;
148 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
149 RenderResult *rr = NULL;
150 bool ok = false;
151
152 if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
153 BKE_image_release_ibuf(ima, ibuf, lock);
154 goto cleanup;
155 }
156
157 ImBuf *colormanaged_ibuf = NULL;
158 const bool save_copy = opts->save_copy;
159 const bool save_as_render = opts->save_as_render;
160 ImageFormatData *imf = &opts->im_format;
161
162 if (ima->type == IMA_TYPE_R_RESULT) {
163 /* enforce user setting for RGB or RGBA, but skip BW */
164 if (opts->im_format.planes == R_IMF_PLANES_RGBA) {
165 ibuf->planes = R_IMF_PLANES_RGBA;
166 }
167 else if (opts->im_format.planes == R_IMF_PLANES_RGB) {
168 ibuf->planes = R_IMF_PLANES_RGB;
169 }
170 }
171 else {
172 /* TODO, better solution, if a 24bit image is painted onto it may contain alpha */
173 if ((opts->im_format.planes == R_IMF_PLANES_RGBA) &&
174 /* it has been painted onto */
175 (ibuf->userflags & IB_BITMAPDIRTY)) {
176 /* checks each pixel, not ideal */
177 ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? R_IMF_PLANES_RGBA : R_IMF_PLANES_RGB;
178 }
179 }
180
181 /* we need renderresult for exr and rendered multiview */
182 rr = BKE_image_acquire_renderresult(opts->scene, ima);
183 bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 :
184 BLI_listbase_count_at_most(&ima->views, 2) < 2;
185 bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
186 RE_HasFloatPixels(rr);
187 bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
188 int layer = (iuser && !is_multilayer) ? iuser->layer : -1;
189
190 /* error handling */
191 if (!rr) {
192 if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
193 BKE_report(reports, RPT_ERROR, "Did not write, no Multilayer Image");
194 BKE_image_release_ibuf(ima, ibuf, lock);
195 goto cleanup;
196 }
197 }
198 else {
199 if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
200 if (!BKE_image_is_stereo(ima)) {
201 BKE_reportf(reports,
202 RPT_ERROR,
203 "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
204 STEREO_LEFT_NAME,
205 STEREO_RIGHT_NAME);
206 BKE_image_release_ibuf(ima, ibuf, lock);
207 goto cleanup;
208 }
209
210 /* it shouldn't ever happen*/
211 if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == NULL) ||
212 (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == NULL)) {
213 BKE_reportf(reports,
214 RPT_ERROR,
215 "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
216 STEREO_LEFT_NAME,
217 STEREO_RIGHT_NAME);
218 BKE_image_release_ibuf(ima, ibuf, lock);
219 goto cleanup;
220 }
221 }
222 BKE_imbuf_stamp_info(rr, ibuf);
223 }
224
225 /* fancy multiview OpenEXR */
226 if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
227 /* save render result */
228 ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
229 image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
230 BKE_image_release_ibuf(ima, ibuf, lock);
231 }
232 /* regular mono pipeline */
233 else if (is_mono) {
234 if (is_exr_rr) {
235 ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
236 }
237 else {
238 colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
239 ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
240 ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy);
241 imbuf_save_post(ibuf, colormanaged_ibuf);
242 }
243 image_save_post(reports,
244 ima,
245 ibuf,
246 ok,
247 opts,
248 (is_exr_rr ? true : save_copy),
249 opts->filepath,
250 r_colorspace_changed);
251 BKE_image_release_ibuf(ima, ibuf, lock);
252 }
253 /* individual multiview images */
254 else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
255 unsigned char planes = ibuf->planes;
256 const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
257
258 if (!is_exr_rr) {
259 BKE_image_release_ibuf(ima, ibuf, lock);
260 }
261
262 for (int i = 0; i < totviews; i++) {
263 char filepath[FILE_MAX];
264 bool ok_view = false;
265 const char *view = rr ? ((RenderView *)BLI_findlink(&rr->views, i))->name :
266 ((ImageView *)BLI_findlink(&ima->views, i))->name;
267
268 if (is_exr_rr) {
269 BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
270 ok_view = RE_WriteRenderResult(reports, rr, filepath, imf, view, layer);
271 image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
272 }
273 else {
274 /* copy iuser to get the correct ibuf for this view */
275 ImageUser view_iuser;
276
277 if (iuser) {
278 /* copy iuser to get the correct ibuf for this view */
279 view_iuser = *iuser;
280 }
281 else {
282 BKE_imageuser_default(&view_iuser);
283 }
284
285 view_iuser.view = i;
286 view_iuser.flag &= ~IMA_SHOW_STEREO;
287
288 if (rr) {
289 BKE_image_multilayer_index(rr, &view_iuser);
290 }
291 else {
292 BKE_image_multiview_index(ima, &view_iuser);
293 }
294
295 ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
296 ibuf->planes = planes;
297
298 BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
299
300 colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
301 ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
302 ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy);
303 imbuf_save_post(ibuf, colormanaged_ibuf);
304 image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
305 BKE_image_release_ibuf(ima, ibuf, lock);
306 }
307 ok &= ok_view;
308 }
309
310 if (is_exr_rr) {
311 BKE_image_release_ibuf(ima, ibuf, lock);
312 }
313 }
314 /* stereo (multiview) images */
315 else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
316 if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
317 ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
318 image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
319 BKE_image_release_ibuf(ima, ibuf, lock);
320 }
321 else {
322 ImBuf *ibuf_stereo[2] = {NULL};
323
324 unsigned char planes = ibuf->planes;
325 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
326
327 /* we need to get the specific per-view buffers */
328 BKE_image_release_ibuf(ima, ibuf, lock);
329
330 for (int i = 0; i < 2; i++) {
331 ImageUser view_iuser;
332
333 if (iuser) {
334 view_iuser = *iuser;
335 }
336 else {
337 BKE_imageuser_default(&view_iuser);
338 }
339
340 view_iuser.flag &= ~IMA_SHOW_STEREO;
341
342 if (rr) {
343 int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
344 view_iuser.view = id;
345 BKE_image_multilayer_index(rr, &view_iuser);
346 }
347 else {
348 view_iuser.view = i;
349 BKE_image_multiview_index(ima, &view_iuser);
350 }
351
352 ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
353
354 if (ibuf == NULL) {
355 BKE_report(
356 reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
357 goto cleanup;
358 }
359
360 ibuf->planes = planes;
361
362 /* color manage the ImBuf leaving it ready for saving */
363 colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
364 ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
365
366 BKE_imbuf_write_prepare(colormanaged_ibuf, imf);
367 IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
368
369 /* duplicate buffer to prevent locker issue when using render result */
370 ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
371
372 imbuf_save_post(ibuf, colormanaged_ibuf);
373 BKE_image_release_ibuf(ima, ibuf, lock);
374 }
375
376 ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
377
378 /* save via traditional path */
379 ok = BKE_imbuf_write_as(ibuf, opts->filepath, imf, save_copy);
380
381 IMB_freeImBuf(ibuf);
382
383 for (int i = 0; i < 2; i++) {
384 IMB_freeImBuf(ibuf_stereo[i]);
385 }
386 }
387 }
388
389 cleanup:
390 if (rr) {
391 BKE_image_release_renderresult(opts->scene, ima);
392 }
393
394 return ok;
395 }
396
BKE_image_save(ReportList * reports,Main * bmain,Image * ima,ImageUser * iuser,ImageSaveOptions * opts)397 bool BKE_image_save(
398 ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts)
399 {
400 ImageUser save_iuser;
401 BKE_imageuser_default(&save_iuser);
402
403 bool colorspace_changed = false;
404
405 if (ima->source == IMA_SRC_TILED) {
406 /* Verify filepath for tiles images. */
407 if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != 1001) {
408 BKE_reportf(reports,
409 RPT_ERROR,
410 "When saving a tiled image, the path '%s' must contain the UDIM tag 1001",
411 opts->filepath);
412 return false;
413 }
414
415 /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
416 if (iuser == NULL) {
417 iuser = &save_iuser;
418 }
419 }
420
421 /* Save image - or, for tiled images, the first tile. */
422 bool ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
423
424 if (ok && ima->source == IMA_SRC_TILED) {
425 char filepath[FILE_MAX];
426 BLI_strncpy(filepath, opts->filepath, sizeof(filepath));
427
428 char head[FILE_MAX], tail[FILE_MAX];
429 unsigned short numlen;
430 BLI_path_sequence_decode(filepath, head, tail, &numlen);
431
432 /* Save all other tiles. */
433 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
434 /* Tile 1001 was already saved before the loop. */
435 if (tile->tile_number == 1001 || !ok) {
436 continue;
437 }
438
439 /* Build filepath of the tile. */
440 BLI_path_sequence_encode(opts->filepath, head, tail, numlen, tile->tile_number);
441
442 iuser->tile = tile->tile_number;
443 ok = ok && image_save_single(reports, ima, iuser, opts, &colorspace_changed);
444 }
445 BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
446 }
447
448 if (colorspace_changed) {
449 BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
450 }
451
452 return ok;
453 }
454