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