Merge branch 'blender2.7'
[blender.git] / source / blender / editors / space_image / image_ops.c
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 spimage
22  */
23
24
25 #include <stddef.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #ifndef WIN32
31 #  include <unistd.h>
32 #else
33 #  include <io.h>
34 #endif
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_math.h"
39 #include "BLI_blenlib.h"
40 #include "BLI_utildefines.h"
41
42 #include "BLT_translation.h"
43
44 #include "DNA_camera_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_node_types.h"
47 #include "DNA_packedFile_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_screen_types.h"
50
51 #include "BKE_colortools.h"
52 #include "BKE_context.h"
53 #include "BKE_icons.h"
54 #include "BKE_image.h"
55 #include "BKE_global.h"
56 #include "BKE_library.h"
57 #include "BKE_main.h"
58 #include "BKE_packedFile.h"
59 #include "BKE_paint.h"
60 #include "BKE_report.h"
61 #include "BKE_screen.h"
62 #include "BKE_sound.h"
63 #include "BKE_scene.h"
64
65 #include "DEG_depsgraph.h"
66
67 #include "GPU_draw.h"
68 #include "GPU_immediate.h"
69
70 #include "IMB_colormanagement.h"
71 #include "IMB_imbuf.h"
72 #include "IMB_imbuf_types.h"
73 #include "IMB_moviecache.h"
74 #include "intern/openexr/openexr_multi.h"
75
76 #include "RE_pipeline.h"
77
78 #include "RNA_access.h"
79 #include "RNA_define.h"
80 #include "RNA_enum_types.h"
81
82 #include "ED_image.h"
83 #include "ED_mask.h"
84 #include "ED_paint.h"
85 #include "ED_render.h"
86 #include "ED_screen.h"
87 #include "ED_space_api.h"
88 #include "ED_uvedit.h"
89 #include "ED_util.h"
90
91 #include "UI_interface.h"
92 #include "UI_resources.h"
93 #include "UI_view2d.h"
94
95 #include "WM_api.h"
96 #include "WM_types.h"
97
98 #include "PIL_time.h"
99
100 #include "RE_engine.h"
101
102 #include "image_intern.h"
103
104 /******************** view navigation utilities *********************/
105
106 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom, const float location[2])
107 {
108         float oldzoom = sima->zoom;
109         int width, height;
110
111         sima->zoom = zoom;
112
113         if (sima->zoom < 0.1f || sima->zoom > 4.0f) {
114                 /* check zoom limits */
115                 ED_space_image_get_size(sima, &width, &height);
116
117                 width *= sima->zoom;
118                 height *= sima->zoom;
119
120                 if ((width < 4) && (height < 4) && sima->zoom < oldzoom) {
121                         sima->zoom = oldzoom;
122                 }
123                 else if (BLI_rcti_size_x(&ar->winrct) <= sima->zoom) {
124                         sima->zoom = oldzoom;
125                 }
126                 else if (BLI_rcti_size_y(&ar->winrct) <= sima->zoom) {
127                         sima->zoom = oldzoom;
128                 }
129         }
130
131         if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) && location) {
132                 float aspx, aspy, w, h;
133
134                 ED_space_image_get_size(sima, &width, &height);
135                 ED_space_image_get_aspect(sima, &aspx, &aspy);
136
137                 w = width * aspx;
138                 h = height * aspy;
139
140                 sima->xof += ((location[0] - 0.5f) * w - sima->xof) * (sima->zoom - oldzoom) / sima->zoom;
141                 sima->yof += ((location[1] - 0.5f) * h - sima->yof) * (sima->zoom - oldzoom) / sima->zoom;
142         }
143 }
144
145 static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac, const float location[2])
146 {
147         sima_zoom_set(sima, ar, sima->zoom * zoomfac, location);
148 }
149
150 /**
151  * Fits the view to the bounds exactly, caller should add margin if needed.
152  */
153 static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *ar, const rctf *bounds)
154 {
155         int image_size[2];
156         float aspx, aspy;
157
158         ED_space_image_get_size(sima, &image_size[0], &image_size[1]);
159         ED_space_image_get_aspect(sima, &aspx, &aspy);
160
161         image_size[0] = image_size[0] * aspx;
162         image_size[1] = image_size[1] * aspy;
163
164         /* adjust offset and zoom */
165         sima->xof = roundf((BLI_rctf_cent_x(bounds) - 0.5f) * image_size[0]);
166         sima->yof = roundf((BLI_rctf_cent_y(bounds) - 0.5f) * image_size[1]);
167
168         float size_xy[2], size;
169         size_xy[0] = BLI_rcti_size_x(&ar->winrct) / (BLI_rctf_size_x(bounds) * image_size[0]);
170         size_xy[1] = BLI_rcti_size_y(&ar->winrct) / (BLI_rctf_size_y(bounds) * image_size[1]);
171
172         size = min_ff(size_xy[0], size_xy[1]);
173         CLAMP_MAX(size, 100.0f);
174
175         sima_zoom_set(sima, ar, size, NULL);
176 }
177
178 #if 0 // currently unused
179 static bool image_poll(bContext *C)
180 {
181         return (CTX_data_edit_image(C) != NULL);
182 }
183 #endif
184
185 static bool space_image_buffer_exists_poll(bContext *C)
186 {
187         SpaceImage *sima = CTX_wm_space_image(C);
188         if (sima && ED_space_image_has_buffer(sima)) {
189                 return true;
190         }
191         return false;
192 }
193
194 static bool image_not_packed_poll(bContext *C)
195 {
196         SpaceImage *sima = CTX_wm_space_image(C);
197
198         /* Do not run 'replace' on packed images, it does not give user expected results at all. */
199         if (sima && sima->image && BLI_listbase_is_empty(&sima->image->packedfiles)) {
200                 return true;
201         }
202         return false;
203 }
204
205 static bool imbuf_format_writeable(const ImBuf *ibuf)
206 {
207         ImageFormatData im_format;
208         ImbFormatOptions options_dummy;
209         BKE_imbuf_to_image_format(&im_format, ibuf);
210         return (BKE_image_imtype_to_ftype(im_format.imtype, &options_dummy) == ibuf->ftype);
211 }
212
213 static bool space_image_file_exists_poll(bContext *C)
214 {
215         if (space_image_buffer_exists_poll(C)) {
216                 Main *bmain = CTX_data_main(C);
217                 SpaceImage *sima = CTX_wm_space_image(C);
218                 ImBuf *ibuf;
219                 void *lock;
220                 bool ret = false;
221                 char name[FILE_MAX];
222
223                 ibuf = ED_space_image_acquire_buffer(sima, &lock);
224                 if (ibuf) {
225                         BLI_strncpy(name, ibuf->name, FILE_MAX);
226                         BLI_path_abs(name, BKE_main_blendfile_path(bmain));
227
228                         if (BLI_exists(name) == false) {
229                                 CTX_wm_operator_poll_msg_set(C, "image file not found");
230                         }
231                         else if (!BLI_file_is_writable(name)) {
232                                 CTX_wm_operator_poll_msg_set(C, "image path can't be written to");
233                         }
234                         else if (!imbuf_format_writeable(ibuf)) {
235                                 CTX_wm_operator_poll_msg_set(C, "image format is read-only");
236                         }
237                         else {
238                                 ret = true;
239                         }
240                 }
241                 ED_space_image_release_buffer(sima, ibuf, lock);
242
243                 return ret;
244         }
245         return false;
246 }
247
248 #if 0  /* UNUSED */
249 static bool space_image_poll(bContext *C)
250 {
251         SpaceImage *sima = CTX_wm_space_image(C);
252         if (sima && sima->image) {
253                 return true;
254         }
255         return false;
256 }
257 #endif
258
259 bool space_image_main_region_poll(bContext *C)
260 {
261         SpaceImage *sima = CTX_wm_space_image(C);
262         /* XXX ARegion *ar = CTX_wm_region(C); */
263
264         if (sima) {
265                 return true;  /* XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW); */
266         }
267         return false;
268 }
269
270 /* For IMAGE_OT_curves_point_set to avoid sampling when in uv smooth mode or editmode */
271 static bool space_image_main_area_not_uv_brush_poll(bContext *C)
272 {
273         SpaceImage *sima = CTX_wm_space_image(C);
274         Scene *scene = CTX_data_scene(C);
275         ToolSettings *toolsettings = scene->toolsettings;
276
277         if (sima && !toolsettings->uvsculpt && (CTX_data_edit_object(C) == NULL)) {
278                 return 1;
279         }
280
281         return 0;
282 }
283
284 static bool image_sample_poll(bContext *C)
285 {
286         SpaceImage *sima = CTX_wm_space_image(C);
287         if (sima) {
288                 Object *obedit = CTX_data_edit_object(C);
289                 if (obedit) {
290                         /* Disable when UV editing so it doesn't swallow all click events (use for setting cursor). */
291                         if (ED_space_image_show_uvedit(sima, obedit)) {
292                                 return false;
293                         }
294                 }
295                 else if (sima->mode != SI_MODE_VIEW) {
296                         return false;
297                 }
298
299                 return space_image_main_region_poll(C);
300         }
301         else {
302                 return false;
303         }
304 }
305 /********************** view pan operator *********************/
306
307 typedef struct ViewPanData {
308         float x, y;
309         float xof, yof;
310         int event_type;
311 } ViewPanData;
312
313 static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
314 {
315         SpaceImage *sima = CTX_wm_space_image(C);
316         ViewPanData *vpd;
317
318         op->customdata = vpd = MEM_callocN(sizeof(ViewPanData), "ImageViewPanData");
319         WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
320
321         vpd->x = event->x;
322         vpd->y = event->y;
323         vpd->xof = sima->xof;
324         vpd->yof = sima->yof;
325         vpd->event_type = event->type;
326
327         WM_event_add_modal_handler(C, op);
328 }
329
330 static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
331 {
332         SpaceImage *sima = CTX_wm_space_image(C);
333         ViewPanData *vpd = op->customdata;
334
335         if (cancel) {
336                 sima->xof = vpd->xof;
337                 sima->yof = vpd->yof;
338                 ED_region_tag_redraw(CTX_wm_region(C));
339         }
340
341         WM_cursor_modal_restore(CTX_wm_window(C));
342         MEM_freeN(op->customdata);
343 }
344
345 static int image_view_pan_exec(bContext *C, wmOperator *op)
346 {
347         SpaceImage *sima = CTX_wm_space_image(C);
348         float offset[2];
349
350         RNA_float_get_array(op->ptr, "offset", offset);
351         sima->xof += offset[0];
352         sima->yof += offset[1];
353
354         ED_region_tag_redraw(CTX_wm_region(C));
355
356         /* XXX notifier? */
357 #if 0
358         if (image_preview_active(curarea, NULL, NULL)) {
359                 /* recalculates new preview rect */
360                 scrarea_do_windraw(curarea);
361                 image_preview_event(2);
362         }
363 #endif
364
365         return OPERATOR_FINISHED;
366 }
367
368 static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
369 {
370         if (event->type == MOUSEPAN) {
371                 SpaceImage *sima = CTX_wm_space_image(C);
372                 float offset[2];
373
374                 offset[0] = (event->prevx - event->x) / sima->zoom;
375                 offset[1] = (event->prevy - event->y) / sima->zoom;
376                 RNA_float_set_array(op->ptr, "offset", offset);
377
378                 image_view_pan_exec(C, op);
379                 return OPERATOR_FINISHED;
380         }
381         else {
382                 image_view_pan_init(C, op, event);
383                 return OPERATOR_RUNNING_MODAL;
384         }
385 }
386
387 static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
388 {
389         SpaceImage *sima = CTX_wm_space_image(C);
390         ViewPanData *vpd = op->customdata;
391         float offset[2];
392
393         switch (event->type) {
394                 case MOUSEMOVE:
395                         sima->xof = vpd->xof;
396                         sima->yof = vpd->yof;
397                         offset[0] = (vpd->x - event->x) / sima->zoom;
398                         offset[1] = (vpd->y - event->y) / sima->zoom;
399                         RNA_float_set_array(op->ptr, "offset", offset);
400                         image_view_pan_exec(C, op);
401                         break;
402                 default:
403                         if (event->type == vpd->event_type && event->val == KM_RELEASE) {
404                                 image_view_pan_exit(C, op, false);
405                                 return OPERATOR_FINISHED;
406                         }
407                         break;
408         }
409
410         return OPERATOR_RUNNING_MODAL;
411 }
412
413 static void image_view_pan_cancel(bContext *C, wmOperator *op)
414 {
415         image_view_pan_exit(C, op, true);
416 }
417
418 void IMAGE_OT_view_pan(wmOperatorType *ot)
419 {
420         /* identifiers */
421         ot->name = "Pan View";
422         ot->idname = "IMAGE_OT_view_pan";
423         ot->description = "Pan the view";
424
425         /* api callbacks */
426         ot->exec = image_view_pan_exec;
427         ot->invoke = image_view_pan_invoke;
428         ot->modal = image_view_pan_modal;
429         ot->cancel = image_view_pan_cancel;
430         ot->poll = space_image_main_region_poll;
431
432         /* flags */
433         ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
434
435         /* properties */
436         RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
437                              "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
438 }
439
440 /********************** view zoom operator *********************/
441
442 typedef struct ViewZoomData {
443         float origx, origy;
444         float zoom;
445         int event_type;
446         float location[2];
447
448         /* needed for continuous zoom */
449         wmTimer *timer;
450         double timer_lastdraw;
451
452         /* */
453         SpaceImage *sima;
454         ARegion *ar;
455 } ViewZoomData;
456
457 static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
458 {
459         SpaceImage *sima = CTX_wm_space_image(C);
460         ARegion *ar = CTX_wm_region(C);
461         ViewZoomData *vpd;
462
463         op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData");
464         WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
465
466         vpd->origx = event->x;
467         vpd->origy = event->y;
468         vpd->zoom = sima->zoom;
469         vpd->event_type = event->type;
470
471         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &vpd->location[0], &vpd->location[1]);
472
473         if (U.viewzoom == USER_ZOOM_CONT) {
474                 /* needs a timer to continue redrawing */
475                 vpd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
476                 vpd->timer_lastdraw = PIL_check_seconds_timer();
477         }
478
479         vpd->sima = sima;
480         vpd->ar = ar;
481
482         WM_event_add_modal_handler(C, op);
483 }
484
485 static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
486 {
487         SpaceImage *sima = CTX_wm_space_image(C);
488         ViewZoomData *vpd = op->customdata;
489
490         if (cancel) {
491                 sima->zoom = vpd->zoom;
492                 ED_region_tag_redraw(CTX_wm_region(C));
493         }
494
495         if (vpd->timer) {
496                 WM_event_remove_timer(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
497         }
498
499         WM_cursor_modal_restore(CTX_wm_window(C));
500         MEM_freeN(op->customdata);
501 }
502
503 static int image_view_zoom_exec(bContext *C, wmOperator *op)
504 {
505         SpaceImage *sima = CTX_wm_space_image(C);
506         ARegion *ar = CTX_wm_region(C);
507
508         sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"), NULL);
509
510         ED_region_tag_redraw(ar);
511
512         /* XXX notifier? */
513 #if 0
514         if (image_preview_active(curarea, NULL, NULL)) {
515                 /* recalculates new preview rect */
516                 scrarea_do_windraw(curarea);
517                 image_preview_event(2);
518         }
519 #endif
520
521         return OPERATOR_FINISHED;
522 }
523
524 enum {
525         VIEW_PASS = 0,
526         VIEW_APPLY,
527         VIEW_CONFIRM,
528 };
529
530 static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
531 {
532         if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
533                 SpaceImage *sima = CTX_wm_space_image(C);
534                 ARegion *ar = CTX_wm_region(C);
535                 float delta, factor, location[2];
536
537                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
538
539                 delta = event->prevx - event->x + event->prevy - event->y;
540
541                 if (U.uiflag & USER_ZOOM_INVERT) {
542                         delta *= -1;
543                 }
544
545                 factor = 1.0f + delta / 300.0f;
546                 RNA_float_set(op->ptr, "factor", factor);
547                 sima_zoom_set(sima, ar, sima->zoom * factor, location);
548                 ED_region_tag_redraw(ar);
549
550                 return OPERATOR_FINISHED;
551         }
552         else {
553                 image_view_zoom_init(C, op, event);
554                 return OPERATOR_RUNNING_MODAL;
555         }
556 }
557
558 static void image_zoom_apply(ViewZoomData *vpd, wmOperator *op, const int x, const int y, const short viewzoom, const short zoom_invert)
559 {
560         float factor;
561
562         if (viewzoom == USER_ZOOM_CONT) {
563                 double time = PIL_check_seconds_timer();
564                 float time_step = (float)(time - vpd->timer_lastdraw);
565                 float fac;
566                 float zfac;
567
568                 if (U.uiflag & USER_ZOOM_HORIZ) {
569                         fac = (float)(x - vpd->origx);
570                 }
571                 else {
572                         fac = (float)(y - vpd->origy);
573                 }
574
575                 if (zoom_invert) {
576                         fac = -fac;
577                 }
578
579                 /* oldstyle zoom */
580                 zfac = 1.0f + ((fac / 20.0f) * time_step);
581                 vpd->timer_lastdraw = time;
582                 /* this is the final zoom, but instead make it into a factor */
583                 //zoom = vpd->sima->zoom * zfac;
584                 factor = (vpd->sima->zoom * zfac) / vpd->zoom;
585         }
586         else {
587                 /* for now do the same things for scale and dolly */
588                 float delta = x - vpd->origx + y - vpd->origy;
589
590                 if (zoom_invert) {
591                         delta *= -1.0f;
592                 }
593
594                 factor = 1.0f + delta / 300.0f;
595         }
596
597         RNA_float_set(op->ptr, "factor", factor);
598         sima_zoom_set(vpd->sima, vpd->ar, vpd->zoom * factor, vpd->location);
599         ED_region_tag_redraw(vpd->ar);
600 }
601
602 static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
603 {
604         ViewZoomData *vpd = op->customdata;
605         short event_code = VIEW_PASS;
606
607         /* execute the events */
608         if (event->type == TIMER && event->customdata == vpd->timer) {
609                 /* continuous zoom */
610                 event_code = VIEW_APPLY;
611         }
612         else if (event->type == MOUSEMOVE) {
613                 event_code = VIEW_APPLY;
614         }
615         else if (event->type == vpd->event_type && event->val == KM_RELEASE) {
616                 event_code = VIEW_CONFIRM;
617         }
618
619         if (event_code == VIEW_APPLY) {
620                 image_zoom_apply(vpd, op, event->x, event->y, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
621         }
622         else if (event_code == VIEW_CONFIRM) {
623                 image_view_zoom_exit(C, op, false);
624                 return OPERATOR_FINISHED;
625         }
626
627         return OPERATOR_RUNNING_MODAL;
628 }
629
630 static void image_view_zoom_cancel(bContext *C, wmOperator *op)
631 {
632         image_view_zoom_exit(C, op, true);
633 }
634
635 void IMAGE_OT_view_zoom(wmOperatorType *ot)
636 {
637         PropertyRNA *prop;
638
639         /* identifiers */
640         ot->name = "Zoom View";
641         ot->idname = "IMAGE_OT_view_zoom";
642         ot->description = "Zoom in/out the image";
643
644         /* api callbacks */
645         ot->exec = image_view_zoom_exec;
646         ot->invoke = image_view_zoom_invoke;
647         ot->modal = image_view_zoom_modal;
648         ot->cancel = image_view_zoom_cancel;
649         ot->poll = space_image_main_region_poll;
650
651         /* flags */
652         ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
653
654         /* properties */
655         prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
656                              "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX);
657         RNA_def_property_flag(prop, PROP_HIDDEN);
658 }
659
660 #ifdef WITH_INPUT_NDOF
661 /********************** NDOF operator *********************/
662
663 /* Combined pan/zoom from a 3D mouse device.
664  * Z zooms, XY pans
665  * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
666  * that explains the negative signs in the code below
667  */
668
669 static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
670 {
671         if (event->type != NDOF_MOTION) {
672                 return OPERATOR_CANCELLED;
673         }
674         else {
675                 SpaceImage *sima = CTX_wm_space_image(C);
676                 ARegion *ar = CTX_wm_region(C);
677                 float pan_vec[3];
678
679                 const wmNDOFMotionData *ndof = event->customdata;
680                 const float speed = NDOF_PIXELS_PER_SECOND;
681
682                 WM_event_ndof_pan_get(ndof, pan_vec, true);
683
684                 mul_v2_fl(pan_vec, (speed * ndof->dt) / sima->zoom);
685                 pan_vec[2] *= -ndof->dt;
686
687                 sima_zoom_set_factor(sima, ar, 1.0f + pan_vec[2], NULL);
688                 sima->xof += pan_vec[0];
689                 sima->yof += pan_vec[1];
690
691                 ED_region_tag_redraw(ar);
692
693                 return OPERATOR_FINISHED;
694         }
695 }
696
697 void IMAGE_OT_view_ndof(wmOperatorType *ot)
698 {
699         /* identifiers */
700         ot->name = "NDOF Pan/Zoom";
701         ot->idname = "IMAGE_OT_view_ndof";
702         ot->description = "Use a 3D mouse device to pan/zoom the view";
703
704         /* api callbacks */
705         ot->invoke = image_view_ndof_invoke;
706         ot->poll = space_image_main_region_poll;
707
708         /* flags */
709         ot->flag = OPTYPE_LOCK_BYPASS;
710 }
711 #endif /* WITH_INPUT_NDOF */
712
713 /********************** view all operator *********************/
714
715 /* Updates the fields of the View2D member of the SpaceImage struct.
716  * Default behavior is to reset the position of the image and set the zoom to 1
717  * If the image will not fit within the window rectangle, the zoom is adjusted */
718
719 static int image_view_all_exec(bContext *C, wmOperator *op)
720 {
721         SpaceImage *sima;
722         ARegion *ar;
723         float aspx, aspy, zoomx, zoomy, w, h;
724         int width, height;
725         const bool fit_view = RNA_boolean_get(op->ptr, "fit_view");
726
727         /* retrieve state */
728         sima = CTX_wm_space_image(C);
729         ar = CTX_wm_region(C);
730
731         ED_space_image_get_size(sima, &width, &height);
732         ED_space_image_get_aspect(sima, &aspx, &aspy);
733
734         w = width * aspx;
735         h = height * aspy;
736
737         /* check if the image will fit in the image with (zoom == 1) */
738         width  = BLI_rcti_size_x(&ar->winrct) + 1;
739         height = BLI_rcti_size_y(&ar->winrct) + 1;
740
741         if (fit_view) {
742                 const int margin = 5; /* margin from border */
743
744                 zoomx = (float) width / (w + 2 * margin);
745                 zoomy = (float) height / (h + 2 * margin);
746
747                 sima_zoom_set(sima, ar, min_ff(zoomx, zoomy), NULL);
748         }
749         else {
750                 if ((w >= width || h >= height) && (width > 0 && height > 0)) {
751                         zoomx = (float) width / w;
752                         zoomy = (float) height / h;
753
754                         /* find the zoom value that will fit the image in the image space */
755                         sima_zoom_set(sima, ar, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL);
756                 }
757                 else {
758                         sima_zoom_set(sima, ar, 1.0f, NULL);
759                 }
760         }
761
762         sima->xof = sima->yof = 0.0f;
763
764         ED_region_tag_redraw(ar);
765
766         return OPERATOR_FINISHED;
767 }
768
769 void IMAGE_OT_view_all(wmOperatorType *ot)
770 {
771         PropertyRNA *prop;
772
773         /* identifiers */
774         ot->name = "View All";
775         ot->idname = "IMAGE_OT_view_all";
776         ot->description = "View the entire image";
777
778         /* api callbacks */
779         ot->exec = image_view_all_exec;
780         ot->poll = space_image_main_region_poll;
781
782         /* flags */
783         ot->flag = OPTYPE_LOCK_BYPASS;
784
785         /* properties */
786         prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
787         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
788 }
789
790 /********************** view selected operator *********************/
791
792 static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
793 {
794         SpaceImage *sima;
795         ARegion *ar;
796         Scene *scene;
797         ViewLayer *view_layer;
798         Object *obedit;
799         Image *ima;
800
801         /* retrieve state */
802         sima = CTX_wm_space_image(C);
803         ar = CTX_wm_region(C);
804         scene = CTX_data_scene(C);
805         view_layer = CTX_data_view_layer(C);
806         obedit = CTX_data_edit_object(C);
807
808         ima = ED_space_image(sima);
809
810         /* get bounds */
811         float min[2], max[2];
812         if (ED_space_image_show_uvedit(sima, obedit)) {
813                 if (!ED_uvedit_minmax(scene, ima, obedit, min, max)) {
814                         return OPERATOR_CANCELLED;
815                 }
816         }
817         else if (ED_space_image_check_show_maskedit(sima, view_layer)) {
818                 if (!ED_mask_selected_minmax(C, min, max)) {
819                         return OPERATOR_CANCELLED;
820                 }
821         }
822         rctf bounds = {
823             .xmin = min[0], .ymin = min[1],
824             .xmax = max[0], .ymax = max[1],
825         };
826
827         /* add some margin */
828         BLI_rctf_scale(&bounds, 1.4f);
829
830         sima_zoom_set_from_bounds(sima, ar, &bounds);
831
832         ED_region_tag_redraw(ar);
833
834         return OPERATOR_FINISHED;
835 }
836
837 static bool image_view_selected_poll(bContext *C)
838 {
839         return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
840 }
841
842 void IMAGE_OT_view_selected(wmOperatorType *ot)
843 {
844         /* identifiers */
845         ot->name = "View Center";
846         ot->idname = "IMAGE_OT_view_selected";
847         ot->description = "View all selected UVs";
848
849         /* api callbacks */
850         ot->exec = image_view_selected_exec;
851         ot->poll = image_view_selected_poll;
852 }
853
854 /********************** view zoom in/out operator *********************/
855
856 static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
857 {
858         SpaceImage *sima = CTX_wm_space_image(C);
859         ARegion *ar = CTX_wm_region(C);
860         float location[2];
861
862         RNA_float_get_array(op->ptr, "location", location);
863
864         sima_zoom_set_factor(sima, ar, powf(2.0f, 1.0f / 3.0f), location);
865
866         ED_region_tag_redraw(ar);
867
868         return OPERATOR_FINISHED;
869 }
870
871 static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
872 {
873         ARegion *ar = CTX_wm_region(C);
874         float location[2];
875
876         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
877         RNA_float_set_array(op->ptr, "location", location);
878
879         return image_view_zoom_in_exec(C, op);
880 }
881
882 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
883 {
884         PropertyRNA *prop;
885
886         /* identifiers */
887         ot->name = "View Zoom In";
888         ot->idname = "IMAGE_OT_view_zoom_in";
889         ot->description = "Zoom in the image (centered around 2D cursor)";
890
891         /* api callbacks */
892         ot->invoke = image_view_zoom_in_invoke;
893         ot->exec = image_view_zoom_in_exec;
894         ot->poll = space_image_main_region_poll;
895
896         /* flags */
897         ot->flag = OPTYPE_LOCK_BYPASS;
898
899         /* properties */
900         prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
901                                     "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
902         RNA_def_property_flag(prop, PROP_HIDDEN);
903 }
904
905 static int image_view_zoom_out_exec(bContext *C, wmOperator *op)
906 {
907         SpaceImage *sima = CTX_wm_space_image(C);
908         ARegion *ar = CTX_wm_region(C);
909         float location[2];
910
911         RNA_float_get_array(op->ptr, "location", location);
912
913         sima_zoom_set_factor(sima, ar, powf(0.5f, 1.0f / 3.0f), location);
914
915         ED_region_tag_redraw(ar);
916
917         return OPERATOR_FINISHED;
918 }
919
920 static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event)
921 {
922         ARegion *ar = CTX_wm_region(C);
923         float location[2];
924
925         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
926         RNA_float_set_array(op->ptr, "location", location);
927
928         return image_view_zoom_out_exec(C, op);
929 }
930
931 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
932 {
933         PropertyRNA *prop;
934
935         /* identifiers */
936         ot->name = "View Zoom Out";
937         ot->idname = "IMAGE_OT_view_zoom_out";
938         ot->description = "Zoom out the image (centered around 2D cursor)";
939
940         /* api callbacks */
941         ot->invoke = image_view_zoom_out_invoke;
942         ot->exec = image_view_zoom_out_exec;
943         ot->poll = space_image_main_region_poll;
944
945         /* flags */
946         ot->flag = OPTYPE_LOCK_BYPASS;
947
948         /* properties */
949         prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
950                                     "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
951         RNA_def_property_flag(prop, PROP_HIDDEN);
952 }
953
954 /********************** view zoom ratio operator *********************/
955
956 static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
957 {
958         SpaceImage *sima = CTX_wm_space_image(C);
959         ARegion *ar = CTX_wm_region(C);
960
961         sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"), NULL);
962
963         /* ensure pixel exact locations for draw */
964         sima->xof = (int)sima->xof;
965         sima->yof = (int)sima->yof;
966
967         /* XXX notifier? */
968 #if 0
969         if (image_preview_active(curarea, NULL, NULL)) {
970                 /* recalculates new preview rect */
971                 scrarea_do_windraw(curarea);
972                 image_preview_event(2);
973         }
974 #endif
975
976         ED_region_tag_redraw(ar);
977
978         return OPERATOR_FINISHED;
979 }
980
981 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
982 {
983         /* identifiers */
984         ot->name = "View Zoom Ratio";
985         ot->idname = "IMAGE_OT_view_zoom_ratio";
986         ot->description = "Set zoom ratio of the view";
987
988         /* api callbacks */
989         ot->exec = image_view_zoom_ratio_exec;
990         ot->poll = space_image_main_region_poll;
991
992         /* flags */
993         ot->flag = OPTYPE_LOCK_BYPASS;
994
995         /* properties */
996         RNA_def_float(ot->srna, "ratio", 0.0f, -FLT_MAX, FLT_MAX,
997                       "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX);
998 }
999
1000 /********************** view border-zoom operator *********************/
1001
1002 static int image_view_zoom_border_exec(bContext *C, wmOperator *op)
1003 {
1004         SpaceImage *sima = CTX_wm_space_image(C);
1005         ARegion *ar = CTX_wm_region(C);
1006         rctf bounds;
1007         const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
1008
1009         WM_operator_properties_border_to_rctf(op, &bounds);
1010
1011         UI_view2d_region_to_view_rctf(&ar->v2d, &bounds, &bounds);
1012
1013         const struct {
1014                 float xof;
1015                 float yof;
1016                 float zoom;
1017         } sima_view_prev = {
1018                 .xof = sima->xof,
1019                 .yof = sima->yof,
1020                 .zoom = sima->zoom,
1021         };
1022
1023         sima_zoom_set_from_bounds(sima, ar, &bounds);
1024
1025         /* zoom out */
1026         if (!zoom_in) {
1027                 sima->xof = sima_view_prev.xof + (sima->xof - sima_view_prev.xof);
1028                 sima->yof = sima_view_prev.yof + (sima->yof - sima_view_prev.yof);
1029                 sima->zoom = sima_view_prev.zoom * (sima_view_prev.zoom / sima->zoom);
1030         }
1031
1032         ED_region_tag_redraw(ar);
1033
1034         return OPERATOR_FINISHED;
1035 }
1036
1037 void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
1038 {
1039         /* identifiers */
1040         ot->name = "Zoom to Border";
1041         ot->description = "Zoom in the view to the nearest item contained in the border";
1042         ot->idname = "IMAGE_OT_view_zoom_border";
1043
1044         /* api callbacks */
1045         ot->invoke = WM_gesture_box_invoke;
1046         ot->exec = image_view_zoom_border_exec;
1047         ot->modal = WM_gesture_box_modal;
1048         ot->cancel = WM_gesture_box_cancel;
1049
1050         ot->poll = space_image_main_region_poll;
1051
1052         /* rna */
1053         WM_operator_properties_gesture_box_zoom(ot);
1054 }
1055
1056 /**************** load/replace/save callbacks ******************/
1057 static void image_filesel(bContext *C, wmOperator *op, const char *path)
1058 {
1059         RNA_string_set(op->ptr, "filepath", path);
1060         WM_event_add_fileselect(C, op);
1061 }
1062
1063 /******************** open image operator ********************/
1064
1065 typedef struct ImageOpenData {
1066         PropertyPointerRNA pprop;
1067         ImageUser *iuser;
1068         ImageFormatData im_format;
1069 } ImageOpenData;
1070
1071 typedef struct ImageFrameRange {
1072         struct ImageFrameRange *next, *prev;
1073         ListBase frames;
1074         /**  The full path of the first file in the list of image files */
1075         char filepath[FILE_MAX];
1076 } ImageFrameRange;
1077
1078 typedef struct ImageFrame {
1079         struct ImageFrame *next, *prev;
1080         int framenr;
1081 } ImageFrame;
1082
1083 static void image_open_init(bContext *C, wmOperator *op)
1084 {
1085         ImageOpenData *iod;
1086         op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
1087         iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
1088         UI_context_active_but_prop_get_templateID(C, &iod->pprop.ptr, &iod->pprop.prop);
1089 }
1090
1091 static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
1092 {
1093         MEM_freeN(op->customdata);
1094         op->customdata = NULL;
1095 }
1096
1097 /**
1098  * \brief Get a list of frames from the list of image files matching the first file name sequence pattern
1099  * \param ptr: [in] the RNA pointer containing the "directory" entry and "files" collection
1100  * \param frames_all: [out] the list of frame numbers found in the files matching the first one by name
1101  */
1102 static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
1103 {
1104         char dir[FILE_MAXDIR];
1105         const bool do_frame_range = RNA_boolean_get(ptr, "use_sequence_detection");
1106         ImageFrameRange *frame_range = NULL;
1107
1108         RNA_string_get(ptr, "directory", dir);
1109         RNA_BEGIN (ptr, itemptr, "files")
1110         {
1111                 char base_head[FILE_MAX], base_tail[FILE_MAX];
1112                 char head[FILE_MAX], tail[FILE_MAX];
1113                 unsigned short digits;
1114                 char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
1115                 ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
1116
1117                 /* use the first file in the list as base filename */
1118                 frame->framenr = BLI_stringdec(filename, head, tail, &digits);
1119
1120                 /* still in the same sequence */
1121                 if (do_frame_range &&
1122                     (frame_range != NULL) &&
1123                     (STREQLEN(base_head, head, FILE_MAX)) &&
1124                     (STREQLEN(base_tail, tail, FILE_MAX)))
1125                 {
1126                         /* pass */
1127                 }
1128                 else {
1129                         /* start a new frame range */
1130                         frame_range = MEM_callocN(sizeof(*frame_range), __func__);
1131                         BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename);
1132                         BLI_addtail(frames_all, frame_range);
1133
1134                         BLI_strncpy(base_head, head, sizeof(base_head));
1135                         BLI_strncpy(base_tail, tail, sizeof(base_tail));
1136                 }
1137
1138                 BLI_addtail(&frame_range->frames, frame);
1139                 MEM_freeN(filename);
1140         }
1141         RNA_END;
1142 }
1143
1144 static int image_cmp_frame(const void *a, const void *b)
1145 {
1146         const ImageFrame *frame_a = a;
1147         const ImageFrame *frame_b = b;
1148
1149         if (frame_a->framenr < frame_b->framenr) {
1150                 return -1;
1151         }
1152         if (frame_a->framenr > frame_b->framenr) {
1153                 return 1;
1154         }
1155         return 0;
1156 }
1157
1158 /**
1159  * Return the start (offset) and the length of the sequence of continuous frames in the list of frames
1160  *
1161  * \param frames: [in] the list of frame numbers, as a side-effect the list is sorted.
1162  * \param ofs: [out] offset the first frame number in the sequence.
1163  * \return the number of contiguous frames in the sequence
1164  */
1165 static int image_sequence_get_len(ListBase *frames, int *ofs)
1166 {
1167         ImageFrame *frame;
1168
1169         BLI_listbase_sort(frames, image_cmp_frame);
1170
1171         frame = frames->first;
1172         if (frame) {
1173                 int frame_curr = frame->framenr;
1174                 (*ofs) = frame_curr;
1175                 while (frame && (frame->framenr == frame_curr)) {
1176                         frame_curr++;
1177                         frame = frame->next;
1178                 }
1179                 return frame_curr - (*ofs);
1180         }
1181         *ofs = 0;
1182         return 0;
1183 }
1184
1185 static Image *image_open_single(
1186         Main *bmain, wmOperator *op, const char *filepath, const char *relbase,
1187         bool is_relative_path, bool use_multiview, int frame_seq_len)
1188 {
1189         bool exists = false;
1190         Image *ima = NULL;
1191
1192         errno = 0;
1193         ima = BKE_image_load_exists_ex(bmain, filepath, &exists);
1194
1195         if (!ima) {
1196                 if (op->customdata) {
1197                         MEM_freeN(op->customdata);
1198                 }
1199                 BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
1200                             filepath, errno ? strerror(errno) : TIP_("unsupported image format"));
1201                 return NULL;
1202         }
1203
1204         if (!exists) {
1205                 /* only image path after save, never ibuf */
1206                 if (is_relative_path) {
1207                         BLI_path_rel(ima->name, relbase);
1208                 }
1209
1210                 /* handle multiview images */
1211                 if (use_multiview) {
1212                         ImageOpenData *iod = op->customdata;
1213                         ImageFormatData *imf = &iod->im_format;
1214
1215                         ima->flag |= IMA_USE_VIEWS;
1216                         ima->views_format = imf->views_format;
1217                         *ima->stereo3d_format = imf->stereo3d_format;
1218                 }
1219                 else {
1220                         ima->flag &= ~IMA_USE_VIEWS;
1221                         BKE_image_free_views(ima);
1222                 }
1223
1224                 if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
1225                         ima->source = IMA_SRC_SEQUENCE;
1226                 }
1227         }
1228
1229         return ima;
1230 }
1231
1232
1233 static int image_open_exec(bContext *C, wmOperator *op)
1234 {
1235         Main *bmain = CTX_data_main(C);
1236         ScrArea *sa = CTX_wm_area(C);
1237         Scene *scene = CTX_data_scene(C);
1238         Object *obedit = CTX_data_edit_object(C);
1239         ImageUser *iuser = NULL;
1240         ImageOpenData *iod = op->customdata;
1241         Image *ima = NULL;
1242         char filepath[FILE_MAX];
1243         int frame_seq_len = 0;
1244         int frame_ofs = 1;
1245
1246         const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
1247         const bool use_multiview    = RNA_boolean_get(op->ptr, "use_multiview");
1248
1249         if (!op->customdata) {
1250                 image_open_init(C, op);
1251         }
1252
1253         RNA_string_get(op->ptr, "filepath", filepath);
1254
1255         if (RNA_struct_property_is_set(op->ptr, "directory") &&
1256             RNA_struct_property_is_set(op->ptr, "files"))
1257         {
1258                 bool was_relative = BLI_path_is_rel(filepath);
1259                 ListBase frame_ranges_all;
1260
1261                 BLI_listbase_clear(&frame_ranges_all);
1262                 image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all);
1263                 for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range; frame_range = frame_range->next) {
1264                         int frame_range_ofs;
1265                         int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs);
1266                         BLI_freelistN(&frame_range->frames);
1267
1268                         char filepath_range[FILE_MAX];
1269                         BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
1270
1271                         if (was_relative) {
1272                                 BLI_path_rel(filepath_range, BKE_main_blendfile_path(bmain));
1273                         }
1274
1275                         Image *ima_range = image_open_single(
1276                                  bmain, op, filepath_range, BKE_main_blendfile_path(bmain),
1277                                  is_relative_path, use_multiview, frame_range_seq_len);
1278
1279                         /* take the first image */
1280                         if ((ima == NULL) && ima_range) {
1281                                 ima = ima_range;
1282                                 frame_seq_len = frame_range_seq_len;
1283                                 frame_ofs = frame_range_ofs;
1284                         }
1285                 }
1286                 BLI_freelistN(&frame_ranges_all);
1287         }
1288         else {
1289                 /* for drag & drop etc. */
1290                 ima = image_open_single(
1291                         bmain, op, filepath, BKE_main_blendfile_path(bmain),
1292                         is_relative_path, use_multiview, 1);
1293         }
1294
1295         if (ima == NULL) {
1296                 return OPERATOR_CANCELLED;
1297         }
1298
1299         /* hook into UI */
1300         iod = op->customdata;
1301
1302         if (iod->pprop.prop) {
1303                 /* when creating new ID blocks, use is already 1, but RNA
1304                  * pointer use also increases user, so this compensates it */
1305                 id_us_min(&ima->id);
1306
1307                 PointerRNA imaptr;
1308                 RNA_id_pointer_create(&ima->id, &imaptr);
1309                 RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr);
1310                 RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
1311         }
1312
1313         if (iod->iuser) {
1314                 iuser = iod->iuser;
1315         }
1316         else if (sa && sa->spacetype == SPACE_IMAGE) {
1317                 SpaceImage *sima = sa->spacedata.first;
1318                 ED_space_image_set(bmain, sima, obedit, ima, false);
1319                 iuser = &sima->iuser;
1320         }
1321         else {
1322                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1323                 if (tex && tex->type == TEX_IMAGE) {
1324                         iuser = &tex->iuser;
1325                 }
1326
1327                 if (iuser == NULL) {
1328                         Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
1329                         if (cam) {
1330                                 for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
1331                                         if (bgpic->ima == ima) {
1332                                                 iuser = &bgpic->iuser;
1333                                                 break;
1334                                         }
1335                                 }
1336                         }
1337                 }
1338         }
1339
1340         /* initialize because of new image */
1341         if (iuser) {
1342                 iuser->frames = frame_seq_len;
1343                 iuser->sfra = 1;
1344                 iuser->framenr = 1;
1345                 if (ima->source == IMA_SRC_MOVIE) {
1346                         iuser->offset = 0;
1347                 }
1348                 else {
1349                         iuser->offset = frame_ofs - 1;
1350                 }
1351                 iuser->scene = scene;
1352                 BKE_image_init_imageuser(ima, iuser);
1353         }
1354
1355         /* XXX unpackImage frees image buffers */
1356         ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1357
1358         BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
1359         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
1360
1361         MEM_freeN(op->customdata);
1362
1363         return OPERATOR_FINISHED;
1364 }
1365
1366 static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1367 {
1368         SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1369         const char *path = U.textudir;
1370         Image *ima = NULL;
1371         Scene *scene = CTX_data_scene(C);
1372
1373         if (sima) {
1374                 ima = sima->image;
1375         }
1376
1377         if (ima == NULL) {
1378                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1379                 if (tex && tex->type == TEX_IMAGE) {
1380                         ima = tex->ima;
1381                 }
1382         }
1383
1384         if (ima == NULL) {
1385                 PointerRNA ptr;
1386                 PropertyRNA *prop;
1387
1388                 /* hook into UI */
1389                 UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
1390
1391                 if (prop) {
1392                         PointerRNA oldptr;
1393                         Image *oldima;
1394
1395                         oldptr = RNA_property_pointer_get(&ptr, prop);
1396                         oldima = (Image *)oldptr.id.data;
1397                         /* unlikely to fail but better avoid strange crash */
1398                         if (oldima && GS(oldima->id.name) == ID_IM) {
1399                                 ima = oldima;
1400                         }
1401                 }
1402         }
1403
1404         if (ima) {
1405                 path = ima->name;
1406         }
1407
1408         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1409                 return image_open_exec(C, op);
1410         }
1411
1412         image_open_init(C, op);
1413
1414         /* show multiview save options only if scene has multiviews */
1415         PropertyRNA *prop;
1416         prop = RNA_struct_find_property(op->ptr, "show_multiview");
1417         RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
1418
1419         image_filesel(C, op, path);
1420
1421         return OPERATOR_RUNNING_MODAL;
1422 }
1423
1424 static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop, void *UNUSED(user_data))
1425 {
1426         const char *prop_id = RNA_property_identifier(prop);
1427
1428         return !(STREQ(prop_id, "filepath") ||
1429                  STREQ(prop_id, "directory") ||
1430                  STREQ(prop_id, "filename")
1431                  );
1432 }
1433
1434 static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
1435 {
1436         uiLayout *layout = op->layout;
1437         ImageOpenData *iod = op->customdata;
1438         ImageFormatData *imf = &iod->im_format;
1439         PointerRNA imf_ptr, ptr;
1440
1441         /* main draw call */
1442         RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
1443         uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
1444
1445         /* image template */
1446         RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
1447
1448         /* multiview template */
1449         if (RNA_boolean_get(op->ptr, "show_multiview")) {
1450                 uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1451         }
1452 }
1453
1454 /* called by other space types too */
1455 void IMAGE_OT_open(wmOperatorType *ot)
1456 {
1457         /* identifiers */
1458         ot->name = "Open Image";
1459         ot->description = "Open image";
1460         ot->idname = "IMAGE_OT_open";
1461
1462         /* api callbacks */
1463         ot->exec = image_open_exec;
1464         ot->invoke = image_open_invoke;
1465         ot->cancel = image_open_cancel;
1466         ot->ui = image_open_draw;
1467
1468         /* flags */
1469         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1470
1471         /* properties */
1472         WM_operator_properties_filesel(
1473                 ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
1474                 WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH,
1475                 FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
1476
1477         RNA_def_boolean(ot->srna, "use_sequence_detection", true, "Detect Sequences",
1478                         "Automatically detect animated sequences in selected images (based on file names)");
1479 }
1480
1481 /******************** Match movie length operator ********************/
1482 static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
1483 {
1484         Scene *scene = CTX_data_scene(C);
1485         Image *ima = CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data;
1486         ImageUser *iuser = CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data;
1487
1488         if (!ima || !iuser) {
1489                 /* Try to get a Texture, or a SpaceImage from context... */
1490                 SpaceImage *sima = CTX_wm_space_image(C);
1491                 Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
1492                 if (tex && tex->type == TEX_IMAGE) {
1493                         ima = tex->ima;
1494                         iuser = &tex->iuser;
1495                 }
1496                 else if (sima) {
1497                         ima = sima->image;
1498                         iuser = &sima->iuser;
1499                 }
1500
1501         }
1502
1503         if (!ima || !iuser || !BKE_image_has_anim(ima)) {
1504                 return OPERATOR_CANCELLED;
1505         }
1506
1507         struct anim *anim = ((ImageAnim *)ima->anims.first)->anim;
1508         if (!anim) {
1509                 return OPERATOR_CANCELLED;
1510         }
1511         iuser->frames = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN);
1512         BKE_image_user_frame_calc(iuser, scene->r.cfra);
1513
1514         return OPERATOR_FINISHED;
1515 }
1516
1517 /* called by other space types too */
1518 void IMAGE_OT_match_movie_length(wmOperatorType *ot)
1519 {
1520         /* identifiers */
1521         ot->name = "Match Movie Length";
1522         ot->description = "Set image's user's length to the one of this video";
1523         ot->idname = "IMAGE_OT_match_movie_length";
1524
1525         /* api callbacks */
1526         ot->exec = image_match_len_exec;
1527
1528         /* flags */
1529         /* Don't think we need undo for that. */
1530         ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL/* | OPTYPE_UNDO */;
1531 }
1532
1533 /******************** replace image operator ********************/
1534
1535 static int image_replace_exec(bContext *C, wmOperator *op)
1536 {
1537         Main *bmain = CTX_data_main(C);
1538         SpaceImage *sima = CTX_wm_space_image(C);
1539         char str[FILE_MAX];
1540
1541         if (!sima->image) {
1542                 return OPERATOR_CANCELLED;
1543         }
1544
1545         RNA_string_get(op->ptr, "filepath", str);
1546
1547         /* we cant do much if the str is longer then FILE_MAX :/ */
1548         BLI_strncpy(sima->image->name, str, sizeof(sima->image->name));
1549
1550         if (sima->image->source == IMA_SRC_GENERATED) {
1551                 sima->image->source = IMA_SRC_FILE;
1552                 BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_SRC_CHANGE);
1553         }
1554
1555         if (BLI_path_extension_check_array(str, imb_ext_movie)) {
1556                 sima->image->source = IMA_SRC_MOVIE;
1557         }
1558         else {
1559                 sima->image->source = IMA_SRC_FILE;
1560         }
1561
1562         /* XXX unpackImage frees image buffers */
1563         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1564
1565         BKE_icon_changed(BKE_icon_id_ensure(&sima->image->id));
1566         BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1567         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
1568
1569         return OPERATOR_FINISHED;
1570 }
1571
1572 static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1573 {
1574         SpaceImage *sima = CTX_wm_space_image(C);
1575
1576         if (!sima->image) {
1577                 return OPERATOR_CANCELLED;
1578         }
1579
1580         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1581                 return image_replace_exec(C, op);
1582         }
1583
1584         if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
1585                 RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->name));
1586         }
1587
1588         image_filesel(C, op, sima->image->name);
1589
1590         return OPERATOR_RUNNING_MODAL;
1591 }
1592
1593 void IMAGE_OT_replace(wmOperatorType *ot)
1594 {
1595         /* identifiers */
1596         ot->name = "Replace Image";
1597         ot->idname = "IMAGE_OT_replace";
1598         ot->description = "Replace current image by another one from disk";
1599
1600         /* api callbacks */
1601         ot->exec = image_replace_exec;
1602         ot->invoke = image_replace_invoke;
1603         ot->poll = image_not_packed_poll;
1604
1605         /* flags */
1606         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1607
1608         /* properties */
1609         WM_operator_properties_filesel(
1610                 ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
1611                 WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
1612 }
1613
1614 /******************** save image as operator ********************/
1615
1616 typedef struct {
1617         /* matching scene->r settings */
1618         //short planes, imtype, subimtype, quality;
1619         ImageFormatData im_format;
1620         char filepath[FILE_MAX]; /* keep absolute */
1621 } SaveImageOptions;
1622
1623 static void save_image_options_defaults(SaveImageOptions *simopts)
1624 {
1625         BKE_imformat_defaults(&simopts->im_format);
1626         simopts->filepath[0] = '\0';
1627 }
1628
1629 static char imtype_best_depth(ImBuf *ibuf, const char imtype)
1630 {
1631         const char depth_ok = BKE_imtype_valid_depths(imtype);
1632
1633         if (ibuf->rect_float) {
1634                 if (depth_ok & R_IMF_CHAN_DEPTH_32) { return R_IMF_CHAN_DEPTH_32; }
1635                 if (depth_ok & R_IMF_CHAN_DEPTH_24) { return R_IMF_CHAN_DEPTH_24; }
1636                 if (depth_ok & R_IMF_CHAN_DEPTH_16) { return R_IMF_CHAN_DEPTH_16; }
1637                 if (depth_ok & R_IMF_CHAN_DEPTH_12) { return R_IMF_CHAN_DEPTH_12; }
1638                 return R_IMF_CHAN_DEPTH_8;
1639         }
1640         else {
1641                 if (depth_ok & R_IMF_CHAN_DEPTH_8)  { return R_IMF_CHAN_DEPTH_8; }
1642                 if (depth_ok & R_IMF_CHAN_DEPTH_12) { return R_IMF_CHAN_DEPTH_12; }
1643                 if (depth_ok & R_IMF_CHAN_DEPTH_16) { return R_IMF_CHAN_DEPTH_16; }
1644                 if (depth_ok & R_IMF_CHAN_DEPTH_24) { return R_IMF_CHAN_DEPTH_24; }
1645                 if (depth_ok & R_IMF_CHAN_DEPTH_32) { return R_IMF_CHAN_DEPTH_32; }
1646                 return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */
1647         }
1648 }
1649
1650 static int save_image_options_init(Main *bmain, SaveImageOptions *simopts, SpaceImage *sima, Scene *scene,
1651                                    const bool guess_path, const bool save_as_render)
1652 {
1653         void *lock;
1654         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
1655
1656         if (ibuf) {
1657                 Image *ima = sima->image;
1658                 bool is_depth_set = false;
1659
1660                 if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
1661                         /* imtype */
1662                         simopts->im_format = scene->r.im_format;
1663                         is_depth_set = true;
1664                         if (!BKE_image_is_multiview(ima)) {
1665                                 /* In case multiview is disabled,
1666                                  * render settings would be invalid for render result in this area. */
1667                                 simopts->im_format.stereo3d_format = *ima->stereo3d_format;
1668                                 simopts->im_format.views_format = ima->views_format;
1669                         }
1670                 }
1671                 else {
1672                         if (ima->source == IMA_SRC_GENERATED) {
1673                                 simopts->im_format.imtype = R_IMF_IMTYPE_PNG;
1674                                 simopts->im_format.compress = ibuf->foptions.quality;
1675                                 simopts->im_format.planes = ibuf->planes;
1676                         }
1677                         else {
1678                                 BKE_imbuf_to_image_format(&simopts->im_format, ibuf);
1679                         }
1680
1681                         /* use the multiview image settings as the default */
1682                         simopts->im_format.stereo3d_format = *ima->stereo3d_format;
1683                         simopts->im_format.views_format = ima->views_format;
1684                 }
1685
1686                 ///* XXX - this is lame, we need to make these available too! */
1687                 //simopts->subimtype = scene->r.subimtype;
1688
1689                 BLI_strncpy(simopts->filepath, ibuf->name, sizeof(simopts->filepath));
1690
1691                 /* sanitize all settings */
1692
1693                 /* unlikely but just in case */
1694                 if (ELEM(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
1695                         simopts->im_format.planes = R_IMF_PLANES_RGBA;
1696                 }
1697
1698                 /* depth, account for float buffer and format support */
1699                 if (is_depth_set == false) {
1700                         simopts->im_format.depth = imtype_best_depth(ibuf, simopts->im_format.imtype);
1701                 }
1702
1703                 /* some formats don't use quality so fallback to scenes quality */
1704                 if (simopts->im_format.quality == 0) {
1705                         simopts->im_format.quality = scene->r.im_format.quality;
1706                 }
1707
1708                 /* check for empty path */
1709                 if (guess_path && simopts->filepath[0] == 0) {
1710                         const bool is_prev_save = !STREQ(G.ima, "//");
1711                         if (save_as_render) {
1712                                 if (is_prev_save) {
1713                                         BLI_strncpy(simopts->filepath, G.ima, sizeof(simopts->filepath));
1714                                 }
1715                                 else {
1716                                         BLI_strncpy(simopts->filepath, "//untitled", sizeof(simopts->filepath));
1717                                         BLI_path_abs(simopts->filepath, BKE_main_blendfile_path(bmain));
1718                                 }
1719                         }
1720                         else {
1721                                 BLI_snprintf(simopts->filepath, sizeof(simopts->filepath), "//%s", ima->id.name + 2);
1722                                 BLI_path_abs(simopts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
1723                         }
1724                 }
1725
1726                 /* color management */
1727                 BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
1728                 BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
1729         }
1730
1731         ED_space_image_release_buffer(sima, ibuf, lock);
1732
1733         return (ibuf != NULL);
1734 }
1735
1736 static void save_image_options_from_op(Main *bmain, SaveImageOptions *simopts, wmOperator *op)
1737 {
1738         if (op->customdata) {
1739                 BKE_color_managed_view_settings_free(&simopts->im_format.view_settings);
1740
1741                 simopts->im_format = *(ImageFormatData *)op->customdata;
1742         }
1743
1744         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1745                 RNA_string_get(op->ptr, "filepath", simopts->filepath);
1746                 BLI_path_abs(simopts->filepath, BKE_main_blendfile_path(bmain));
1747         }
1748 }
1749
1750 static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op)
1751 {
1752         if (op->customdata) {
1753                 BKE_color_managed_view_settings_free(&((ImageFormatData *)op->customdata)->view_settings);
1754
1755                 *(ImageFormatData *)op->customdata = simopts->im_format;
1756         }
1757
1758         RNA_string_set(op->ptr, "filepath", simopts->filepath);
1759 }
1760
1761 static void save_image_post(
1762         Main *bmain, wmOperator *op, ImBuf *ibuf, Image *ima, int ok, int save_copy,
1763         const char *relbase, int relative, int do_newpath, const char *filepath)
1764 {
1765         if (ok) {
1766                 if (!save_copy) {
1767                         ColorManagedColorspaceSettings old_colorspace_settings;
1768
1769                         if (do_newpath) {
1770                                 BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
1771                                 BLI_strncpy(ima->name, filepath, sizeof(ima->name));
1772                         }
1773
1774                         ibuf->userflags &= ~IB_BITMAPDIRTY;
1775
1776                         /* change type? */
1777                         if (ima->type == IMA_TYPE_R_RESULT) {
1778                                 ima->type = IMA_TYPE_IMAGE;
1779
1780                                 /* workaround to ensure the render result buffer is no longer used
1781                                  * by this image, otherwise can crash when a new render result is
1782                                  * created. */
1783                                 if (ibuf->rect && !(ibuf->mall & IB_rect)) {
1784                                         imb_freerectImBuf(ibuf);
1785                                 }
1786                                 if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat)) {
1787                                         imb_freerectfloatImBuf(ibuf);
1788                                 }
1789                                 if (ibuf->zbuf && !(ibuf->mall & IB_zbuf)) {
1790                                         IMB_freezbufImBuf(ibuf);
1791                                 }
1792                                 if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat)) {
1793                                         IMB_freezbuffloatImBuf(ibuf);
1794                                 }
1795                         }
1796                         if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
1797                                 ima->source = IMA_SRC_FILE;
1798                                 ima->type = IMA_TYPE_IMAGE;
1799                         }
1800
1801                         /* only image path, never ibuf */
1802                         if (relative) {
1803                                 BLI_path_rel(ima->name, relbase); /* only after saving */
1804                         }
1805
1806                         BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings,
1807                                                                    &ima->colorspace_settings);
1808                         IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
1809                         if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
1810                                                                           &ima->colorspace_settings))
1811                         {
1812                                 BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
1813                         }
1814                 }
1815         }
1816         else {
1817                 BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
1818         }
1819 }
1820
1821 static void save_imbuf_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
1822 {
1823         if (colormanaged_ibuf != ibuf) {
1824                 /* This guys might be modified by image buffer write functions,
1825                  * need to copy them back from color managed image buffer to an
1826                  * original one, so file type of image is being properly updated.
1827                  */
1828                 ibuf->ftype = colormanaged_ibuf->ftype;
1829                 ibuf->foptions = colormanaged_ibuf->foptions;
1830                 ibuf->planes = colormanaged_ibuf->planes;
1831
1832                 IMB_freeImBuf(colormanaged_ibuf);
1833         }
1834 }
1835
1836 /**
1837  * \return success.
1838  * \note ``ima->name`` and ``ibuf->name`` should end up the same.
1839  * \note for multiview the first ``ibuf`` is important to get the settings.
1840  */
1841 static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath)
1842 {
1843         Main *bmain = CTX_data_main(C);
1844         Image *ima = ED_space_image(sima);
1845         void *lock;
1846         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
1847         Scene *scene;
1848         RenderResult *rr = NULL;
1849         bool ok = false;
1850
1851         WM_cursor_wait(1);
1852
1853         if (ibuf) {
1854                 ImBuf *colormanaged_ibuf = NULL;
1855                 const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id);
1856                 const bool relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path"));
1857                 const bool save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
1858                 const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render"));
1859                 ImageFormatData *imf = &simopts->im_format;
1860
1861                 /* old global to ensure a 2nd save goes to same dir */
1862                 BLI_strncpy(G.ima, simopts->filepath, sizeof(G.ima));
1863
1864                 if (ima->type == IMA_TYPE_R_RESULT) {
1865                         /* enforce user setting for RGB or RGBA, but skip BW */
1866                         if (simopts->im_format.planes == R_IMF_PLANES_RGBA) {
1867                                 ibuf->planes = R_IMF_PLANES_RGBA;
1868                         }
1869                         else if (simopts->im_format.planes == R_IMF_PLANES_RGB) {
1870                                 ibuf->planes = R_IMF_PLANES_RGB;
1871                         }
1872                 }
1873                 else {
1874                         /* TODO, better solution, if a 24bit image is painted onto it may contain alpha */
1875                         if ((simopts->im_format.planes == R_IMF_PLANES_RGBA) &&
1876                             /* it has been painted onto */
1877                             (ibuf->userflags & IB_BITMAPDIRTY))
1878                         {
1879                                 /* checks each pixel, not ideal */
1880                                 ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? R_IMF_PLANES_RGBA : R_IMF_PLANES_RGB;
1881                         }
1882                 }
1883
1884                 /* we need renderresult for exr and rendered multiview */
1885                 scene = CTX_data_scene(C);
1886                 rr = BKE_image_acquire_renderresult(scene, ima);
1887                 bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 : BLI_listbase_count_at_most(&ima->views, 2) < 2;
1888                 bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr);
1889                 bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
1890                 int layer = (is_multilayer) ? -1 : sima->iuser.layer;
1891
1892                 /* error handling */
1893                 if (!rr) {
1894                         if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
1895                                 BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
1896                                 goto cleanup;
1897                         }
1898                 }
1899                 else {
1900                         if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
1901                                 if (!BKE_image_is_stereo(ima)) {
1902                                         BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
1903                                                    STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
1904                                         goto cleanup;
1905                                 }
1906
1907                                 /* it shouldn't ever happen*/
1908                                 if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == NULL) ||
1909                                     (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == NULL))
1910                                 {
1911                                         BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
1912                                                    STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
1913                                         goto cleanup;
1914                                 }
1915                         }
1916                         BKE_imbuf_stamp_info(rr, ibuf);
1917                 }
1918
1919                 /* fancy multiview OpenEXR */
1920                 if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
1921                         /* save render result */
1922                         ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, NULL, layer);
1923                         save_image_post(bmain, op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
1924                         ED_space_image_release_buffer(sima, ibuf, lock);
1925                 }
1926                 /* regular mono pipeline */
1927                 else if (is_mono) {
1928                         if (is_exr_rr) {
1929                                 ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, NULL, layer);
1930                         }
1931                         else {
1932                                 colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
1933                                 ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, imf, save_copy);
1934                                 save_imbuf_post(ibuf, colormanaged_ibuf);
1935                         }
1936                         save_image_post(bmain, op, ibuf, ima, ok, (is_exr_rr ? true : save_copy), relbase, relative, do_newpath, simopts->filepath);
1937                         ED_space_image_release_buffer(sima, ibuf, lock);
1938                 }
1939                 /* individual multiview images */
1940                 else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
1941                         int i;
1942                         unsigned char planes = ibuf->planes;
1943                         const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
1944
1945                         if (!is_exr_rr) {
1946                                 ED_space_image_release_buffer(sima, ibuf, lock);
1947                         }
1948
1949                         for (i = 0; i < totviews; i++) {
1950                                 char filepath[FILE_MAX];
1951                                 bool ok_view = false;
1952                                 const char *view = rr ? ((RenderView *) BLI_findlink(&rr->views, i))->name :
1953                                                         ((ImageView *) BLI_findlink(&ima->views, i))->name;
1954
1955                                 if (is_exr_rr) {
1956                                         BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
1957                                         ok_view = RE_WriteRenderResult(op->reports, rr, filepath, imf, view, layer);
1958                                         save_image_post(bmain, op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
1959                                 }
1960                                 else {
1961                                         /* copy iuser to get the correct ibuf for this view */
1962                                         ImageUser iuser = sima->iuser;
1963                                         iuser.view = i;
1964                                         iuser.flag &= ~IMA_SHOW_STEREO;
1965
1966                                         if (rr) {
1967                                                 BKE_image_multilayer_index(rr, &iuser);
1968                                         }
1969                                         else {
1970                                                 BKE_image_multiview_index(ima, &iuser);
1971                                         }
1972
1973                                         ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
1974                                         ibuf->planes = planes;
1975
1976                                         BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
1977
1978                                         colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
1979                                         ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &simopts->im_format, save_copy);
1980                                         save_imbuf_post(ibuf, colormanaged_ibuf);
1981                                         save_image_post(bmain, op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
1982                                         BKE_image_release_ibuf(sima->image, ibuf, lock);
1983                                 }
1984                                 ok &= ok_view;
1985                         }
1986
1987                         if (is_exr_rr) {
1988                                 ED_space_image_release_buffer(sima, ibuf, lock);
1989                         }
1990                 }
1991                 /* stereo (multiview) images */
1992                 else if (simopts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
1993                         if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
1994                                 ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, NULL, layer);
1995                                 save_image_post(bmain, op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
1996                                 ED_space_image_release_buffer(sima, ibuf, lock);
1997                         }
1998                         else {
1999                                 ImBuf *ibuf_stereo[2] = {NULL};
2000
2001                                 unsigned char planes = ibuf->planes;
2002                                 const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
2003                                 int i;
2004
2005                                 /* we need to get the specific per-view buffers */
2006                                 ED_space_image_release_buffer(sima, ibuf, lock);
2007
2008                                 for (i = 0; i < 2; i ++) {
2009                                         ImageUser iuser = sima->iuser;
2010                                         iuser.flag &= ~IMA_SHOW_STEREO;
2011
2012                                         if (rr) {
2013                                                 int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
2014                                                 iuser.view = id;
2015                                                 BKE_image_multilayer_index(rr, &iuser);
2016                                         }
2017                                         else {
2018                                                 iuser.view = i;
2019                                                 BKE_image_multiview_index(ima, &iuser);
2020                                         }
2021
2022                                         ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
2023
2024                                         if (ibuf == NULL) {
2025                                                 BKE_report(op->reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
2026                                                 goto cleanup;
2027                                         }
2028
2029                                         ibuf->planes = planes;
2030
2031                                         /* color manage the ImBuf leaving it ready for saving */
2032                                         colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true,
2033                                                                                                 &imf->view_settings, &imf->display_settings, imf);
2034
2035                                         BKE_imbuf_write_prepare(colormanaged_ibuf, imf);
2036                                         IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
2037
2038                                         /* duplicate buffer to prevent locker issue when using render result */
2039                                         ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
2040
2041                                         save_imbuf_post(ibuf, colormanaged_ibuf);
2042                                         BKE_image_release_ibuf(sima->image, ibuf, lock);
2043                                 }
2044
2045                                 ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
2046
2047                                 /* save via traditional path */
2048                                 ok = BKE_imbuf_write_as(ibuf, simopts->filepath, imf, save_copy);
2049
2050                                 IMB_freeImBuf(ibuf);
2051
2052                                 for (i = 0; i < 2; i ++) {
2053                                         IMB_freeImBuf(ibuf_stereo[i]);
2054                                 }
2055                         }
2056                 }
2057
2058                 WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
2059
2060         }
2061         else {
2062 cleanup:
2063                 ED_space_image_release_buffer(sima, ibuf, lock);
2064         }
2065
2066         if (rr) {
2067                 BKE_image_release_renderresult(scene, ima);
2068         }
2069
2070         WM_cursor_wait(0);
2071
2072         return ok;
2073 }
2074
2075 static void image_save_as_free(wmOperator *op)
2076 {
2077         if (op->customdata) {
2078                 ImageFormatData *im_format = (ImageFormatData *)op->customdata;
2079                 BKE_color_managed_view_settings_free(&im_format->view_settings);
2080
2081                 MEM_freeN(op->customdata);
2082                 op->customdata = NULL;
2083         }
2084 }
2085
2086 static int image_save_as_exec(bContext *C, wmOperator *op)
2087 {
2088         Main *bmain = CTX_data_main(C);
2089         SpaceImage *sima = CTX_wm_space_image(C);
2090         SaveImageOptions simopts;
2091
2092         save_image_options_defaults(&simopts);
2093
2094         /* just in case to initialize values,
2095          * these should be set on invoke or by the caller. */
2096         save_image_options_init(bmain, &simopts, sima, CTX_data_scene(C), false, false);
2097
2098         save_image_options_from_op(bmain, &simopts, op);
2099
2100         save_image_doit(C, sima, op, &simopts, true);
2101
2102         image_save_as_free(op);
2103         return OPERATOR_FINISHED;
2104 }
2105
2106
2107 static bool image_save_as_check(bContext *UNUSED(C), wmOperator *op)
2108 {
2109         ImageFormatData *imf = op->customdata;
2110         return WM_operator_filesel_ensure_ext_imtype(op, imf);
2111 }
2112
2113 static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2114 {
2115         Main *bmain = CTX_data_main(C);
2116         SpaceImage *sima = CTX_wm_space_image(C);
2117         Image *ima = ED_space_image(sima);
2118         Scene *scene = CTX_data_scene(C);
2119         SaveImageOptions simopts;
2120         PropertyRNA *prop;
2121         const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) || (ima->flag & IMA_VIEW_AS_RENDER));
2122
2123         if (RNA_struct_property_is_set(op->ptr, "filepath")) {
2124                 return image_save_as_exec(C, op);
2125         }
2126
2127         save_image_options_defaults(&simopts);
2128
2129         if (save_image_options_init(bmain, &simopts, sima, scene, true, save_as_render) == 0) {
2130                 return OPERATOR_CANCELLED;
2131         }
2132         save_image_options_to_op(&simopts, op);
2133
2134         /* enable save_copy by default for render results */
2135         if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) && !RNA_struct_property_is_set(op->ptr, "copy")) {
2136                 RNA_boolean_set(op->ptr, "copy", true);
2137         }
2138
2139         RNA_boolean_set(op->ptr, "save_as_render", save_as_render);
2140
2141         op->customdata = MEM_mallocN(sizeof(simopts.im_format), __func__);
2142         memcpy(op->customdata, &simopts.im_format, sizeof(simopts.im_format));
2143
2144         /* show multiview save options only if image has multiviews */
2145         prop = RNA_struct_find_property(op->ptr, "show_multiview");
2146         RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
2147         prop = RNA_struct_find_property(op->ptr, "use_multiview");
2148         RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
2149
2150         image_filesel(C, op, simopts.filepath);
2151
2152         return OPERATOR_RUNNING_MODAL;
2153 }
2154
2155 static void image_save_as_cancel(bContext *UNUSED(C), wmOperator *op)
2156 {
2157         image_save_as_free(op);
2158 }
2159
2160 static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data))
2161 {
2162         const char *prop_id = RNA_property_identifier(prop);
2163
2164         return !(STREQ(prop_id, "filepath") ||
2165                  STREQ(prop_id, "directory") ||
2166                  STREQ(prop_id, "filename") ||
2167                  /* when saving a copy, relative path has no effect */
2168                  ((STREQ(prop_id, "relative_path")) && RNA_boolean_get(ptr, "copy"))
2169                  );
2170 }
2171
2172 static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
2173 {
2174         uiLayout *layout = op->layout;
2175         ImageFormatData *imf = op->customdata;
2176         PointerRNA imf_ptr, ptr;
2177         const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
2178
2179         /* image template */
2180         RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
2181         uiTemplateImageSettings(layout, &imf_ptr, false);
2182
2183         /* main draw call */
2184         RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
2185         uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
2186
2187         /* multiview template */
2188         if (is_multiview) {
2189                 uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
2190         }
2191 }
2192
2193 static bool image_save_as_poll(bContext *C)
2194 {
2195         if (space_image_buffer_exists_poll(C)) {
2196                 if (G.is_rendering) {
2197                         /* no need to NULL check here */
2198                         SpaceImage *sima = CTX_wm_space_image(C);
2199                         Image *ima = ED_space_image(sima);
2200
2201                         if (ima->source == IMA_SRC_VIEWER) {
2202                                 CTX_wm_operator_poll_msg_set(C, "can't save image while rendering");
2203                                 return false;
2204                         }
2205                 }
2206                 return true;
2207         }
2208         return false;
2209 }
2210
2211 void IMAGE_OT_save_as(wmOperatorType *ot)
2212 {
2213         /* identifiers */
2214         ot->name = "Save As Image";
2215         ot->idname = "IMAGE_OT_save_as";
2216         ot->description = "Save the image with another name and/or settings";
2217
2218         /* api callbacks */
2219         ot->exec = image_save_as_exec;
2220         ot->check = image_save_as_check;
2221         ot->invoke = image_save_as_invoke;
2222         ot->cancel = image_save_as_cancel;
2223         ot->ui = image_save_as_draw;
2224         ot->poll = image_save_as_poll;
2225
2226         /* flags */
2227         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2228
2229         /* properties */
2230         RNA_def_boolean(ot->srna, "save_as_render", 0, "Save As Render", "Apply render part of display transform when saving byte image");
2231         RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender");
2232
2233         WM_operator_properties_filesel(
2234                 ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
2235                 WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
2236 }
2237
2238 /******************** save image operator ********************/
2239
2240 static int image_save_exec(bContext *C, wmOperator *op)
2241 {
2242         Main *bmain = CTX_data_main(C);
2243         SpaceImage *sima = CTX_wm_space_image(C);
2244         Scene *scene = CTX_data_scene(C);
2245         SaveImageOptions simopts;
2246
2247         save_image_options_defaults(&simopts);
2248         if (save_image_options_init(bmain, &simopts, sima, scene, false, false) == 0) {
2249                 return OPERATOR_CANCELLED;
2250         }
2251         save_image_options_from_op(bmain, &simopts, op);
2252
2253         if (BLI_exists(simopts.filepath) && BLI_file_is_writable(simopts.filepath)) {
2254                 if (save_image_doit(C, sima, op, &simopts, false)) {
2255                         /* report since this can be called from key-shortcuts */
2256                         BKE_reportf(op->reports, RPT_INFO, "Saved Image '%s'", simopts.filepath);
2257                 }
2258         }
2259         else {
2260                 BKE_reportf(op->reports, RPT_ERROR, "Cannot save image, path '%s' is not writable", simopts.filepath);
2261                 return OPERATOR_CANCELLED;
2262         }
2263
2264         return OPERATOR_FINISHED;
2265 }
2266
2267 void IMAGE_OT_save(wmOperatorType *ot)
2268 {
2269         /* identifiers */
2270         ot->name = "Save Image";
2271         ot->idname = "IMAGE_OT_save";
2272         ot->description = "Save the image with current name and settings";
2273
2274         /* api callbacks */
2275         ot->exec = image_save_exec;
2276         ot->poll = space_image_file_exists_poll;
2277
2278         /* flags */
2279         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2280 }
2281
2282 /******************* save sequence operator ********************/
2283
2284 static int image_save_sequence_exec(bContext *C, wmOperator *op)
2285 {
2286         Main *bmain = CTX_data_main(C);
2287         SpaceImage *sima = CTX_wm_space_image(C);
2288         ImBuf *ibuf, *first_ibuf = NULL;
2289         int tot = 0;
2290         char di[FILE_MAX];
2291         struct MovieCacheIter *iter;
2292
2293         if (sima->image == NULL) {
2294                 return OPERATOR_CANCELLED;
2295         }
2296
2297         if (sima->image->source != IMA_SRC_SEQUENCE) {
2298                 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
2299                 return OPERATOR_CANCELLED;
2300         }
2301
2302         if (sima->image->type == IMA_TYPE_MULTILAYER) {
2303                 BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences");
2304                 return OPERATOR_CANCELLED;
2305         }
2306
2307         /* get total dirty buffers and first dirty buffer which is used for menu */
2308         ibuf = NULL;
2309         if (sima->image->cache != NULL) {
2310                 iter = IMB_moviecacheIter_new(sima->image->cache);
2311                 while (!IMB_moviecacheIter_done(iter)) {
2312                         ibuf = IMB_moviecacheIter_getImBuf(iter);
2313                         if (ibuf->userflags & IB_BITMAPDIRTY) {
2314                                 if (first_ibuf == NULL) {
2315                                         first_ibuf = ibuf;
2316                                 }
2317                                 tot++;
2318                         }
2319                         IMB_moviecacheIter_step(iter);
2320                 }
2321                 IMB_moviecacheIter_free(iter);
2322         }
2323
2324         if (tot == 0) {
2325                 BKE_report(op->reports, RPT_WARNING, "No images have been changed");
2326                 return OPERATOR_CANCELLED;
2327         }
2328
2329         /* get a filename for menu */
2330         BLI_split_dir_part(first_ibuf->name, di, sizeof(di));
2331         BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
2332
2333         iter = IMB_moviecacheIter_new(sima->image->cache);
2334         while (!IMB_moviecacheIter_done(iter)) {
2335                 ibuf = IMB_moviecacheIter_getImBuf(iter);
2336
2337                 if (ibuf->userflags & IB_BITMAPDIRTY) {
2338                         char name[FILE_MAX];
2339                         BLI_strncpy(name, ibuf->name, sizeof(name));
2340
2341                         BLI_path_abs(name, BKE_main_blendfile_path(bmain));
2342
2343                         if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
2344                                 BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
2345                                 break;
2346                         }
2347
2348                         BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->name);
2349                         ibuf->userflags &= ~IB_BITMAPDIRTY;
2350                 }
2351
2352                 IMB_moviecacheIter_step(iter);
2353         }
2354         IMB_moviecacheIter_free(iter);
2355
2356         return OPERATOR_FINISHED;
2357 }
2358
2359 void IMAGE_OT_save_sequence(wmOperatorType *ot)
2360 {
2361         /* identifiers */
2362         ot->name = "Save Sequence";
2363         ot->idname = "IMAGE_OT_save_sequence";
2364         ot->description = "Save a sequence of images";
2365
2366         /* api callbacks */
2367         ot->exec = image_save_sequence_exec;
2368         ot->poll = space_image_buffer_exists_poll;
2369
2370         /* flags */
2371         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2372 }
2373
2374 /******************** reload image operator ********************/
2375
2376 static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
2377 {
2378         Main *bmain = CTX_data_main(C);
2379         Image *ima = CTX_data_edit_image(C);
2380         SpaceImage *sima = CTX_wm_space_image(C);
2381
2382         if (!ima) {
2383                 return OPERATOR_CANCELLED;
2384         }
2385
2386         /* XXX unpackImage frees image buffers */
2387         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2388
2389         BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
2390         DEG_id_tag_update(&ima->id, 0);
2391
2392         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2393
2394         return OPERATOR_FINISHED;
2395 }
2396
2397 void IMAGE_OT_reload(wmOperatorType *ot)
2398 {
2399         /* identifiers */
2400         ot->name = "Reload Image";
2401         ot->idname = "IMAGE_OT_reload";
2402         ot->description = "Reload current image from disk";
2403
2404         /* api callbacks */
2405         ot->exec = image_reload_exec;
2406
2407         /* flags */
2408         ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
2409 }
2410
2411 /********************** new image operator *********************/
2412 #define IMA_DEF_NAME N_("Untitled")
2413
2414 enum {
2415         GEN_CONTEXT_NONE = 0,
2416         GEN_CONTEXT_PAINT_CANVAS = 1,
2417         GEN_CONTEXT_PAINT_STENCIL = 2,
2418 };
2419
2420 typedef struct ImageNewData {
2421         PropertyPointerRNA pprop;
2422 } ImageNewData;
2423
2424 static ImageNewData *image_new_init(bContext *C, wmOperator *op)
2425 {
2426         if (op->customdata) {
2427                 return op->customdata;
2428         }
2429
2430         ImageNewData *data = MEM_callocN(sizeof(ImageNewData), __func__);
2431         UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2432         op->customdata = data;
2433         return data;
2434 }
2435
2436 static void image_new_free(wmOperator *op)
2437 {
2438         if (op->customdata) {
2439                 MEM_freeN(op->customdata);
2440                 op->customdata = NULL;
2441         }
2442 }
2443
2444 static int image_new_exec(bContext *C, wmOperator *op)
2445 {
2446         SpaceImage *sima;
2447         Object *obedit;
2448         Image *ima;
2449         Main *bmain;
2450         PropertyRNA *prop;
2451         char name_buffer[MAX_ID_NAME - 2];
2452         const char *name;
2453         float color[4];
2454         int width, height, floatbuf, gen_type, alpha;
2455         int stereo3d;
2456
2457         /* retrieve state */
2458         sima = CTX_wm_space_image(C);
2459         obedit = CTX_data_edit_object(C);
2460         bmain = CTX_data_main(C);
2461
2462         prop = RNA_struct_find_property(op->ptr, "name");
2463         RNA_property_string_get(op->ptr, prop, name_buffer);
2464         if (!RNA_property_is_set(op->ptr, prop)) {
2465                 /* Default value, we can translate! */
2466                 name = DATA_(name_buffer);
2467         }
2468         else {
2469                 name = name_buffer;
2470         }
2471         width = RNA_int_get(op->ptr, "width");
2472         height = RNA_int_get(op->ptr, "height");
2473         floatbuf = RNA_boolean_get(op->ptr, "float");
2474         gen_type = RNA_enum_get(op->ptr, "generated_type");
2475         RNA_float_get_array(op->ptr, "color", color);
2476         alpha = RNA_boolean_get(op->ptr, "alpha");
2477         stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
2478
2479         if (!alpha) {
2480                 color[3] = 1.0f;
2481         }
2482
2483         ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
2484
2485         if (!ima) {
2486                 image_new_free(op);
2487                 return OPERATOR_CANCELLED;
2488         }
2489
2490         /* hook into UI */
2491         ImageNewData *data = image_new_init(C, op);
2492
2493         if (data->pprop.prop) {
2494                 /* when creating new ID blocks, use is already 1, but RNA
2495                  * pointer use also increases user, so this compensates it */
2496                 id_us_min(&ima->id);
2497
2498                 PointerRNA imaptr;
2499                 RNA_id_pointer_create(&ima->id, &imaptr);
2500                 RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr);
2501                 RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
2502         }
2503         else if (sima) {
2504                 ED_space_image_set(bmain, sima, obedit, ima, false);
2505         }
2506
2507         BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
2508
2509         WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
2510
2511         image_new_free(op);
2512
2513         return OPERATOR_FINISHED;
2514 }
2515
2516 static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2517 {
2518         /* Get property in advance, it doesn't work after WM_operator_props_dialog_popup. */
2519         ImageNewData *data;
2520         op->customdata = data = MEM_callocN(sizeof(ImageNewData), __func__);
2521         UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2522
2523         /* Better for user feedback. */
2524         RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2525         return WM_operator_props_dialog_popup(C, op, 300, 100);
2526 }
2527
2528 static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
2529 {
2530         uiLayout *split, *col[2];
2531         uiLayout *layout = op->layout;
2532         PointerRNA ptr;
2533 #if 0
2534         Scene *scene = CTX_data_scene(C);
2535         const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2536 #endif
2537
2538         RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
2539
2540         /* copy of WM_operator_props_dialog_popup() layout */
2541
2542         split = uiLayoutSplit(layout, 0.5f, false);
2543         col[0] = uiLayoutColumn(split, false);
2544         col[1] = uiLayoutColumn(split, false);
2545
2546         uiItemL(col[0], IFACE_("Name"), ICON_NONE);
2547         uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
2548
2549         uiItemL(col[0], IFACE_("Width"), ICON_NONE);
2550         uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
2551
2552         uiItemL(col[0], IFACE_("Height"), ICON_NONE);
2553         uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
2554
2555         uiItemL(col[0], IFACE_("Color"), ICON_NONE);
2556         uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
2557
2558         uiItemL(col[0], "", ICON_NONE);
2559         uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
2560
2561         uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
2562         uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
2563
2564         uiItemL(col[0], "", ICON_NONE);
2565         uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
2566
2567 #if 0
2568         if (is_multiview) {
2569                 uiItemL(col[0], "", ICON_NONE);
2570                 uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
2571         }
2572 #endif
2573 }
2574
2575 static void image_new_cancel(bContext *UNUSED(C), wmOperator *op)
2576 {
2577         image_new_free(op);
2578 }
2579
2580 void IMAGE_OT_new(wmOperatorType *ot)
2581 {
2582         PropertyRNA *prop;
2583         static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2584
2585         /* identifiers */
2586         ot->name = "New Image";
2587         ot->description = "Create a new image";
2588         ot->idname = "IMAGE_OT_new";
2589
2590         /* api callbacks */
2591         ot->exec = image_new_exec;
2592         ot->invoke = image_new_invoke;
2593         ot->ui = image_new_draw;
2594         ot->cancel = image_new_cancel;
2595
2596         /* flags */
2597         ot->flag = OPTYPE_UNDO;
2598
2599         /* properties */
2600         RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
2601         prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2602         RNA_def_property_subtype(prop, PROP_PIXEL);
2603         prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2604         RNA_def_property_subtype(prop, PROP_PIXEL);
2605         prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2606         RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
2607         RNA_def_property_float_array_default(prop, default_color);
2608         RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
2609         RNA_def_enum(ot->srna, "generated_type", rna_enum_image_generated_type_items, IMA_GENTYPE_BLANK,
2610                      "Generated Type", "Fill the image with a grid for UV map testing");
2611         RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
2612         RNA_def_property_flag(prop, PROP_HIDDEN);
2613         prop = RNA_def_boolean(ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
2614         RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
2615 }
2616
2617 #undef IMA_DEF_NAME
2618
2619 /********************* invert operators *********************/
2620
2621 static bool image_invert_poll(bContext *C)
2622 {
2623         Image *ima = CTX_data_edit_image(C);
2624
2625         return BKE_image_has_ibuf(ima, NULL);
2626 }
2627
2628 static int image_invert_exec(bContext *C, wmOperator *op)
2629 {
2630         Image *ima = CTX_data_edit_image(C);
2631         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2632         SpaceImage *sima = CTX_wm_space_image(C);
2633         /* undo is supported only on image paint mode currently */
2634         bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
2635
2636         /* flags indicate if this channel should be inverted */
2637         const bool r = RNA_boolean_get(op->ptr, "invert_r");
2638         const bool g = RNA_boolean_get(op->ptr, "invert_g");
2639         const bool b = RNA_boolean_get(op->ptr, "invert_b");
2640         const bool a = RNA_boolean_get(op->ptr, "invert_a");
2641
2642         size_t i;
2643
2644         if (ibuf == NULL) {
2645                 /* TODO: this should actually never happen, but does for render-results -> cleanup */
2646                 return OPERATOR_CANCELLED;
2647         }
2648
2649         if (support_undo) {
2650                 ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
2651                 /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
2652                  * but better do this right in case someone copies this for a tool that uses partial
2653                  * redraw better */
2654                 ED_imapaint_clear_partial_redraw();
2655                 ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
2656         }
2657         /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
2658         if (ibuf->rect_float) {
2659
2660                 float *fp = (float *) ibuf->rect_float;
2661                 for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
2662                         if (r) { fp[0] = 1.0f - fp[0]; }
2663                         if (g) { fp[1] = 1.0f - fp[1]; }
2664                         if (b) { fp[2] = 1.0f - fp[2]; }
2665                         if (a) { fp[3] = 1.0f - fp[3]; }
2666                 }
2667
2668                 if (ibuf->rect) {
2669                         IMB_rect_from_float(ibuf);
2670                 }
2671         }
2672         else if (ibuf->rect) {
2673
2674                 char *cp = (char *) ibuf->rect;
2675                 for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
2676                         if (r) { cp[0] = 255 - cp[0]; }
2677                         if (g) { cp[1] = 255 - cp[1]; }
2678                         if (b) { cp[2] = 255 - cp[2]; }
2679                         if (a) { cp[3] = 255 - cp[3]; }
2680                 }
2681         }
2682         else {
2683                 BKE_image_release_ibuf(ima, ibuf, NULL);
2684                 return OPERATOR_CANCELLED;
2685         }
2686
2687         ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID;
2688
2689         if (ibuf->mipmap[0]) {
2690                 ibuf->userflags |= IB_MIPMAP_INVALID;
2691         }
2692
2693         if (support_undo) {
2694                 ED_image_undo_push_end();
2695         }
2696
2697         /* force GPU reupload, all image is invalid */
2698         GPU_free_image(ima);
2699
2700         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2701
2702         BKE_image_release_ibuf(ima, ibuf, NULL);
2703
2704         return OPERATOR_FINISHED;
2705 }
2706
2707 void IMAGE_OT_invert(wmOperatorType *ot)
2708 {
2709         PropertyRNA *prop;
2710
2711         /* identifiers */
2712         ot->name = "Invert Channels";
2713         ot->idname = "IMAGE_OT_invert";
2714         ot->description = "Invert image's channels";
2715
2716         /* api callbacks */
2717         ot->exec = image_invert_exec;
2718         ot->poll = image_invert_poll;
2719
2720         /* properties */
2721         prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
2722         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2723         prop = RNA_def_boolean(ot->srna, "invert_g", 0, "Green", "Invert Green Channel");
2724         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2725         prop = RNA_def_boolean(ot->srna, "invert_b", 0, "Blue", "Invert Blue Channel");
2726         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2727         prop = RNA_def_boolean(ot->srna, "invert_a", 0, "Alpha", "Invert Alpha Channel");
2728         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
2729
2730         /* flags */
2731         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2732 }
2733
2734 /********************* pack operator *********************/
2735
2736 static bool image_pack_test(bContext *C, wmOperator *op)
2737 {
2738         Image *ima = CTX_data_edit_image(C);
2739         const bool as_png = RNA_boolean_get(op->ptr, "as_png");
2740
2741         if (!ima) {
2742                 return 0;
2743         }
2744         if (!as_png && BKE_image_has_packedfile(ima)) {
2745                 return 0;
2746         }
2747
2748         if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2749                 BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
2750                 return 0;
2751         }
2752
2753         return 1;
2754 }
2755
2756 static int image_pack_exec(bContext *C, wmOperator *op)
2757 {
2758         struct Main *bmain = CTX_data_main(C);
2759         Image *ima = CTX_data_edit_image(C);
2760         ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2761         const bool as_png = RNA_boolean_get(op->ptr, "as_png");
2762
2763         if (!image_pack_test(C, op)) {
2764                 return OPERATOR_CANCELLED;
2765         }
2766
2767         if (!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
2768                 BKE_report(op->reports, RPT_ERROR, "Cannot pack edited image from disk, only as internal PNG");
2769                 return OPERATOR_CANCELLED;
2770         }
2771
2772         if (as_png) {
2773                 BKE_image_memorypack(ima);
2774         }
2775         else {
2776                 BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
2777         }
2778
2779         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2780
2781         BKE_image_release_ibuf(ima, ibuf, NULL);
2782
2783         return OPERATOR_FINISHED;
2784 }
2785
2786 static int image_pack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2787 {
2788         Image *ima = CTX_data_edit_image(C);
2789         ImBuf *ibuf;
2790         uiPopupMenu *pup;
2791         uiLayout *layout;
2792         const bool as_png = RNA_boolean_get(op->ptr, "as_png");
2793
2794         if (!image_pack_test(C, op)) {
2795                 return OPERATOR_CANCELLED;
2796         }
2797
2798         ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
2799
2800         if (!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
2801                 pup = UI_popup_menu_begin(C, IFACE_("OK"), ICON_QUESTION);
2802                 layout = UI_popup_menu_layout(pup);
2803                 uiItemBooleanO(layout, IFACE_("Can't pack edited image from disk, pack as internal PNG?"), ICON_NONE,
2804                                op->idname, "as_png", 1);
2805                 UI_popup_menu_end(C, pup);
2806
2807                 BKE_image_release_ibuf(ima, ibuf, NULL);
2808
2809                 return OPERATOR_INTERFACE;
2810         }
2811
2812         BKE_image_release_ibuf(ima, ibuf, NULL);
2813
2814         return image_pack_exec(C, op);
2815 }
2816
2817 void IMAGE_OT_pack(wmOperatorType *ot)
2818 {
2819         /* identifiers */
2820         ot->name = "Pack Image";
2821         ot->description = "Pack an image as embedded data into the .blend file";
2822         ot->idname = "IMAGE_OT_pack";
2823
2824         /* api callbacks */
2825         ot->exec = image_pack_exec;
2826         ot->invoke = image_pack_invoke;
2827
2828         /* flags */
2829         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2830
2831         /* properties */
2832         RNA_def_boolean(ot->srna, "as_png", 0, "Pack As PNG", "Pack image as lossless PNG");
2833 }
2834
2835 /********************* unpack operator *********************/
2836
2837 static int image_unpack_exec(bContext *C, wmOperator *op)
2838 {
2839         Image *ima = CTX_data_edit_image(C);
2840         int method = RNA_enum_get(op->ptr, "method");
2841
2842         /* find the suppplied image by name */
2843         if (RNA_struct_property_is_set(op->ptr, "id")) {
2844                 char imaname[MAX_ID_NAME - 2];
2845                 RNA_string_get(op->ptr, "id", imaname);
2846                 ima = BLI_findstring(&CTX_data_main(C)->images, imaname, offsetof(ID, name) + 2);
2847                 if (!ima) {
2848                         ima = CTX_data_edit_image(C);
2849                 }
2850         }
2851
2852         if (!ima || !BKE_image_has_packedfile(ima)) {
2853                 return OPERATOR_CANCELLED;
2854         }
2855
2856         if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2857                 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2858                 return OPERATOR_CANCELLED;
2859         }
2860
2861         if (G.fileflags & G_FILE_AUTOPACK) {
2862                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
2863         }
2864
2865         /* XXX unpackImage frees image buffers */
2866         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2867
2868         unpackImage(CTX_data_main(C), op->reports, ima, method);
2869
2870         WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
2871
2872         return OPERATOR_FINISHED;
2873 }
2874
2875 static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2876 {
2877         Image *ima = CTX_data_edit_image(C);
2878
2879         if (RNA_struct_property_is_set(op->ptr, "id")) {
2880                 return image_unpack_exec(C, op);
2881         }
2882
2883         if (!ima || !BKE_image_has_packedfile(ima)) {
2884                 return OPERATOR_CANCELLED;
2885         }
2886
2887         if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
2888                 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
2889                 return OPERATOR_CANCELLED;
2890         }
2891
2892         if (G.fileflags & G_FILE_AUTOPACK) {
2893                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
2894         }
2895
2896         unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", BKE_image_has_packedfile(ima) ? ((ImagePackedFile *)ima->packedfiles.first)->packedfile : NULL);
2897
2898         return OPERATOR_FINISHED;
2899 }
2900
2901 void IMAGE_OT_unpack(wmOperatorType *ot)
2902 {
2903         /* identifiers */
2904         ot->name = "Unpack Image";
2905         ot->description = "Save an image packed in the .blend file to disk";
2906         ot->idname = "IMAGE_OT_unpack";
2907
2908         /* api callbacks */
2909         ot->exec = image_unpack_exec;
2910         ot->invoke = image_unpack_invoke;
2911
2912         /* flags */
2913         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2914
2915         /* properties */
2916         RNA_def_enum(ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
2917         /* XXX, weak!, will fail with library, name collisions */
2918         RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
2919 }
2920
2921 /******************** sample image operator ********************/
2922
2923 typedef struct ImageSampleInfo {
2924         ARegionType *art;
2925         void *draw_handle;
2926         int x, y;
2927         int channels;
2928
2929         int width, height;
2930         int sample_size;
2931
2932         unsigned char col[4];
2933         float colf[4];
2934         float linearcol[4];
2935         int z;
2936         float zf;
2937
2938         unsigned char *colp;
2939         const float *colfp;
2940         int *zp;
2941         float *zfp;
2942
2943         bool draw;
2944         bool color_manage;
2945         int use_default_view;
2946 } ImageSampleInfo;
2947
2948 static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
2949 {
2950         ImageSampleInfo *info = arg_info;
2951         if (!info->draw) {
2952                 return;
2953         }
2954
2955         Scene *scene = CTX_data_scene(C);
2956         ED_image_draw_info(
2957                 scene, ar, info->color_manage, info->use_default_view, info->channels,
2958                 info->x, info->y, info->colp, info->colfp, info->linearcol, info->zp, info->zfp);
2959
2960         if (info->sample_size > 1) {
2961                 const wmWindow *win = CTX_wm_window(C);
2962                 const wmEvent *event = win->eventstate;
2963
2964                 SpaceImage *sima = CTX_wm_space_image(C);
2965                 GPUVertFormat *format = immVertexFormat();
2966                 uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2967
2968                 const float color[3] = {1, 1, 1};
2969                 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
2970                 immUniformColor3fv(color);
2971
2972                 /* TODO(campbell): lock to pixels. */
2973                 rctf sample_rect_fl;
2974                 BLI_rctf_init_pt_radius(
2975                         &sample_rect_fl,
2976                         (float[2]){event->x - ar->winrct.xmin, event->y - ar->winrct.ymin},
2977                         (float)(info->sample_size / 2.0f) * sima->zoom);
2978
2979                 glEnable(GL_COLOR_LOGIC_OP);
2980                 glLogicOp(GL_XOR);
2981                 imm_draw_box_wire_2d(
2982                         pos,
2983                         (float)sample_rect_fl.xmin,
2984                         (float)sample_rect_fl.ymin,
2985                         (float)sample_rect_fl.xmax,
2986                         (float)sample_rect_fl.ymax);
2987                 glDisable(GL_COLOR_LOGIC_OP);
2988
2989                 immUnbindProgram();
2990         }
2991 }
2992
2993 /* Returns color in linear space, matching ED_space_node_color_sample(). */
2994 bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
2995 {
2996         void *lock;
2997         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
2998         float fx, fy;
2999         bool ret = false;
3000
3001         if (ibuf == NULL) {
3002                 ED_space_image_release_buffer(sima, ibuf, lock);
3003                 return false;
3004         }
3005
3006         UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fx, &fy);
3007
3008         if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
3009                 const float *fp;
3010                 unsigned char *cp;
3011                 int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
3012
3013                 CLAMP(x, 0, ibuf->x - 1);
3014                 CLAMP(y, 0, ibuf->y - 1);
3015
3016                 if (ibuf->rect_float) {
3017                         fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
3018                         copy_v3_v3(r_col, fp);
3019                         ret = true;
3020                 }
3021                 else if (ibuf->rect) {
3022                         cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
3023                         rgb_uchar_to_float(r_col, cp);
3024                         IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
3025                         ret = true;
3026                 }
3027         }
3028
3029         ED_space_image_release_buffer(sima, ibuf, lock);
3030         return ret;
3031 }
3032
3033
3034 /* -------------------------------------------------------------------- */
3035 /** \name Image Pixel Sample
3036  * \{ */
3037
3038 static void image_sample_pixel_color_ubyte(
3039         const ImBuf *ibuf, const int coord[2],
3040         uchar r_col[4], float r_col_linear[4])
3041 {
3042         const uchar *cp = (unsigned char *)(ibuf->rect + coord[1] * ibuf->x + coord[0]);
3043         copy_v4_v4_uchar(r_col, cp);
3044         rgba_uchar_to_float(r_col_linear, r_col);
3045         IMB_colormanagement_colorspace_to_scene_linear_v4(r_col_linear, false, ibuf->rect_colorspace);
3046 }
3047
3048 static void image_sample_pixel_color_float(
3049         ImBuf *ibuf, const int coord[2],
3050         float r_col[4])
3051 {
3052         const float *cp = ibuf->rect_float + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
3053         copy_v4_v4(r_col, cp);
3054 }
3055
3056 /** \} */
3057
3058 /* -------------------------------------------------------------------- */
3059 /** \name Image Pixel Region Sample
3060  * \{ */
3061
3062 static void image_sample_rect_color_ubyte(
3063         const ImBuf *ibuf, const rcti *rect,
3064         uchar r_col[4], float r_col_linear[4])
3065 {
3066         uint col_accum_ub[4] = {0, 0, 0, 0};
3067         zero_v4(r_col_linear);
3068         int col_tot = 0;
3069         int coord[2];
3070         for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
3071                 for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
3072                         float col_temp_fl[4];
3073                         uchar col_temp_ub[4];
3074                         image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
3075                         add_v4_v4(r_col_linear, col_temp_fl);
3076                         col_accum_ub[0] += (uint)col_temp_ub[0];
3077                         col_accum_ub[1] += (uint)col_temp_ub[1];
3078                         col_accum_ub[2] += (uint)col_temp_ub[2];
3079                         col_accum_ub[3] += (uint)col_temp_ub[3];
3080                         col_tot += 1;
3081                 }
3082         }
3083         mul_v4_fl(r_col_linear, 1.0 / (float)col_tot);
3084
3085         r_col[0] = MIN2(col_accum_ub[0] / col_tot, 255);
3086         r_col[1] = MIN2(col_accum_ub[1] / col_tot, 255);
3087         r_col[2] = MIN2(col_accum_ub[2] / col_tot, 255);
3088         r_col[3] = MIN2(col_accum_ub[3] / col_tot, 255);
3089 }
3090
3091
3092 static void image_sample_rect_color_float(
3093         ImBuf *ibuf, const rcti *rect,
3094         float r_col[4])
3095 {
3096         zero_v4(r_col);
3097         int col_tot = 0;
3098         int coord[2];
3099         for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
3100                 for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
3101                         float col_temp_fl[4];
3102                         image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
3103                         add_v4_v4(r_col, col_temp_fl);
3104                         col_tot += 1;
3105                 }
3106         }
3107         mul_v4_fl(r_col, 1.0 / (float)col_tot);
3108 }
3109
3110 /** \} */
3111
3112 static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
3113 {
3114         SpaceImage *sima = CTX_wm_space_image(C);
3115         ARegion *ar = CTX_wm_region(C);
3116         void *lock;
3117         ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
3118         ImageSampleInfo *info = op->customdata;
3119         float fx, fy;
3120         Scene *scene = CTX_data_scene(C);
3121         CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
3122
3123         if (ibuf == NULL) {
3124                 ED_space_image_release_buffer(sima, ibuf, lock);
3125                 info->draw = false;
3126                 return;
3127         }
3128
3129         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
3130
3131         if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
3132                 int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
3133                 Image *image = ED_space_image(sima);
3134
3135                 CLAMP(x, 0, ibuf->x - 1);
3136                 CLAMP(y, 0, ibuf->y - 1);
3137
3138                 info->width = ibuf->x;
3139                 info->height = ibuf->y;
3140                 info->x = x;
3141                 info->y = y;
3142
3143                 info->draw = true;
3144                 info->channels = ibuf->channels;
3145
3146                 info->colp = NULL;
3147                 info->colfp = NULL;
3148                 info->zp = NULL;
3149                 info->zfp = NULL;
3150
3151                 info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
3152
3153                 rcti sample_rect;
3154                 sample_rect.xmin = max_ii(0, x - info->sample_size / 2);
3155                 sample_rect.ymin = max_ii(0, y - info->sample_size / 2);
3156                 sample_rect.xmax = min_ii(ibuf->x, sample_rect.xmin + info->sample_size) - 1;
3157                 sample_rect.ymax = min_ii(ibuf->y, sample_rect.ymin + info->sample_size) - 1;
3158
3159                 if (ibuf->rect) {
3160                         image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
3161                         rgba_uchar_to_float(info->colf, info->col);
3162
3163                         info->colp = info->col;
3164                         info->colfp = info->colf;
3165                         info->color_manage = true;
3166                 }
3167                 if (ibuf->rect_float) {
3168                         image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
3169
3170                         if (ibuf->channels == 4) {
3171                                 /* pass */
3172                         }
3173                         else if (ibuf->channels == 3) {
3174                                 info->colf[3] = 1.0f;
3175                         }
3176                         else {
3177                                 info->colf[1] = info->colf[0];
3178                                 info->colf[2] = info->colf[0];
3179                                 info->colf[3] = 1.0f;
3180                         }
3181                         info->colfp = info->colf;
3182
3183                         copy_v4_v4(info->linearcol, info->colf);
3184
3185                         info->color_manage = true;
3186                 }
3187
3188                 if (ibuf->zbuf) {
3189                         /* TODO, blend depth (not urgent). */
3190                         info->z = ibuf->zbuf[y * ibuf->x + x];
3191                         info->zp = &info->z;
3192                         if (ibuf->zbuf == (int *)ibuf->rect) {
3193                                 info->colp = NULL;
3194                         }
3195                 }
3196                 if (ibuf->zbuf_float) {
3197                         /* TODO, blend depth (not urgent). */
3198                         info->zf = ibuf->zbuf_float[y * ibuf->x + x];
3199                         info->zfp = &info->zf;
3200                         if (ibuf->zbuf_float == ibuf->rect_float) {
3201                                 info->colfp = NULL;
3202                         }
3203                 }
3204
3205                 if (curve_mapping && ibuf->channels == 4) {
3206                         /* we reuse this callback for set curves point operators */
3207                         if (RNA_struct_find_property(op->ptr, "point")) {
3208                                 int point = RNA_enum_get(op->ptr, "point");
3209
3210                                 if (point == 1) {
3211                                         curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
3212                                 }
3213                                 else if (point == 0) {
3214                                         curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
3215                                 }
3216                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
3217                         }
3218                 }
3219
3220                 // XXX node curve integration ..
3221 #if 0
3222                 {
3223                         ScrArea *sa, *cur = curarea;
3224
3225                         node_curvemap_sample(fp);   /* sends global to node editor */
3226                         for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
3227                                 if (sa->spacetype == SPACE_NODE) {
3228                                         areawinset(sa->win);
3229                                         scrarea_do_windraw(sa);
3230                                 }
3231                         }
3232                         node_curvemap_sample(NULL);     /* clears global in node editor */
3233                         curarea = cur;
3234                 }
3235 #endif
3236         }
3237         else {
3238                 info->draw = 0;
3239         }
3240
3241         ED_space_image_release_buffer(sima, ibuf, lock);
3242         ED_area_tag_redraw(CTX_wm_area(C));
3243 }
3244
3245 static void image_sample_exit(bContext *C, wmOperator *op)
3246 {
3247         ImageSampleInfo *info = op->customdata;
3248
3249         ED_region_draw_cb_exit(info->art, info->draw_handle);
3250         ED_area_tag_redraw(CTX_wm_area(C));
3251         MEM_freeN(info);
3252 }
3253
3254 static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3255 {
3256         SpaceImage *sima = CTX_wm_space_image(C);
3257         ARegion *ar = CTX_wm_region(C);
3258         ImageSampleInfo *info;
3259
3260         if (ar->regiontype == RGN_TYPE_WINDOW) {
3261                 if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
3262                         return OPERATOR_PASS_THROUGH;
3263                 }
3264         }
3265
3266         if (!ED_space_image_has_buffer(sima)) {
3267                 return OPERATOR_CANCELLED;
3268         }
3269
3270         info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
3271
3272         info->art = ar->type;
3273         info->draw_handle = ED_region_draw_cb_activate(ar->type, image_sample_draw, info, REGION_DRAW_POST_PIXEL);
3274         info->sample_size = RNA_int_get(op->ptr, "size");
3275         op->customdata = info;
3276
3277         image_sample_apply(C, op, event);
3278
3279         WM_event_add_