Blender V4.5
image_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cerrno>
10#include <cstddef>
11#include <cstdlib>
12#include <cstring>
13#include <fcntl.h>
14#include <string>
15#ifndef WIN32
16# include <unistd.h>
17#else
18# include <io.h>
19#endif
20
21#include "MEM_guardedalloc.h"
22
23#include "BLI_fileops.h"
24#include "BLI_listbase.h"
25#include "BLI_path_utils.hh"
26#include "BLI_set.hh"
27#include "BLI_string.h"
28#include "BLI_time.h"
29#include "BLI_utildefines.h"
30
31#include "BLT_translation.hh"
32
33#include "DNA_camera_types.h"
34#include "DNA_node_types.h"
35#include "DNA_object_types.h"
36#include "DNA_scene_types.h"
37#include "DNA_screen_types.h"
38
39#include "BKE_colortools.hh"
40#include "BKE_context.hh"
41#include "BKE_global.hh"
42#include "BKE_icons.h"
43#include "BKE_image.hh"
44#include "BKE_image_format.hh"
45#include "BKE_image_save.hh"
46#include "BKE_layer.hh"
47#include "BKE_lib_id.hh"
48#include "BKE_library.hh"
49#include "BKE_main.hh"
50#include "BKE_mask.h"
51#include "BKE_packedFile.hh"
52#include "BKE_report.hh"
53#include "BKE_scene.hh"
54
55#include "DEG_depsgraph.hh"
56
58#include "IMB_imbuf.hh"
59#include "IMB_imbuf_types.hh"
60#include "IMB_moviecache.hh"
61
62#include "MOV_read.hh"
63
64#include "RE_pipeline.h"
65
66#include "RNA_access.hh"
67#include "RNA_define.hh"
68#include "RNA_enum_types.hh"
69#include "RNA_prototypes.hh"
70
71#include "ED_image.hh"
72#include "ED_mask.hh"
73#include "ED_paint.hh"
74#include "ED_render.hh"
75#include "ED_screen.hh"
76#include "ED_undo.hh"
77#include "ED_util.hh"
78#include "ED_util_imbuf.hh"
79#include "ED_uvedit.hh"
80
81#include "UI_interface.hh"
82#include "UI_resources.hh"
83#include "UI_view2d.hh"
84
85#include "WM_api.hh"
86#include "WM_types.hh"
87
88#include "RE_engine.h"
89
90#include "image_intern.hh"
91
92using blender::Vector;
93
94/* -------------------------------------------------------------------- */
97
98static void sima_zoom_set(
99 SpaceImage *sima, ARegion *region, float zoom, const float location[2], const bool zoom_to_pos)
100{
101 float oldzoom = sima->zoom;
102 int width, height;
103
104 sima->zoom = zoom;
105
106 if (sima->zoom < 0.1f || sima->zoom > 4.0f) {
107 /* check zoom limits */
108 ED_space_image_get_size(sima, &width, &height);
109
110 width *= sima->zoom;
111 height *= sima->zoom;
112
113 if ((width < 4) && (height < 4) && sima->zoom < oldzoom) {
114 sima->zoom = oldzoom;
115 }
116 else if (BLI_rcti_size_x(&region->winrct) <= sima->zoom) {
117 sima->zoom = oldzoom;
118 }
119 else if (BLI_rcti_size_y(&region->winrct) <= sima->zoom) {
120 sima->zoom = oldzoom;
121 }
122 }
123
124 if (zoom_to_pos && location) {
125 float aspx, aspy, w, h;
126
127 ED_space_image_get_size(sima, &width, &height);
128 ED_space_image_get_aspect(sima, &aspx, &aspy);
129
130 w = width * aspx;
131 h = height * aspy;
132
133 sima->xof += ((location[0] - 0.5f) * w - sima->xof) * (sima->zoom - oldzoom) / sima->zoom;
134 sima->yof += ((location[1] - 0.5f) * h - sima->yof) * (sima->zoom - oldzoom) / sima->zoom;
135 }
136}
137
139 ARegion *region,
140 float zoomfac,
141 const float location[2],
142 const bool zoom_to_pos)
143{
144 sima_zoom_set(sima, region, sima->zoom * zoomfac, location, zoom_to_pos);
145}
146
150static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *region, const rctf *bounds)
151{
152 int image_size[2];
153 float aspx, aspy;
154
155 ED_space_image_get_size(sima, &image_size[0], &image_size[1]);
156 ED_space_image_get_aspect(sima, &aspx, &aspy);
157
158 image_size[0] = image_size[0] * aspx;
159 image_size[1] = image_size[1] * aspy;
160
161 /* adjust offset and zoom */
162 sima->xof = roundf((BLI_rctf_cent_x(bounds) - 0.5f) * image_size[0]);
163 sima->yof = roundf((BLI_rctf_cent_y(bounds) - 0.5f) * image_size[1]);
164
165 float size_xy[2], size;
166 size_xy[0] = BLI_rcti_size_x(&region->winrct) / (BLI_rctf_size_x(bounds) * image_size[0]);
167 size_xy[1] = BLI_rcti_size_y(&region->winrct) / (BLI_rctf_size_y(bounds) * image_size[1]);
168
169 size = min_ff(size_xy[0], size_xy[1]);
170 CLAMP_MAX(size, 100.0f);
171
172 sima_zoom_set(sima, region, size, nullptr, false);
173}
174
176{
177 /* Edit image is set by templates used throughout the interface, so image
178 * operations work outside the image editor. */
179 Image *ima = static_cast<Image *>(CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data);
180
181 if (ima) {
182 return ima;
183 }
184
185 /* Image editor. */
187 return (sima) ? sima->image : nullptr;
188}
189
191{
192 /* Edit image user is set by templates used throughout the interface, so
193 * image operations work outside the image editor. */
194 ImageUser *iuser = static_cast<ImageUser *>(
195 CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data);
196
197 if (iuser) {
198 return iuser;
199 }
200
201 /* Image editor. */
203 return (sima) ? &sima->iuser : nullptr;
204}
205
207{
208 /* Try to get image user from context if available, otherwise use default. */
209 ImageUser *iuser_context = image_user_from_context(C);
210 ImageUser iuser;
211 if (iuser_context) {
212 iuser = *iuser_context;
213 }
214 else {
215 BKE_imageuser_default(&iuser);
216 }
217
218 /* Use the file associated with the active tile. Otherwise use the first tile. */
219 if (ima && ima->source == IMA_SRC_TILED) {
221 iuser.tile = active ? active->tile_number : ((ImageTile *)ima->tiles.first)->tile_number;
222 }
223
224 return iuser;
225}
226
228{
229 Image *ima = image_from_context(C);
231
232 if (ima == nullptr) {
233 return false;
234 }
235
236 void *lock;
237 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
238 const bool has_buffer = (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data));
239 BKE_image_release_ibuf(ima, ibuf, lock);
240 return has_buffer;
241}
242
247{
248 Image *ima = image_from_context(C);
249
250 if (ima && !ID_IS_EDITABLE(&ima->id)) {
251 CTX_wm_operator_poll_msg_set(C, "Image is not editable");
252 return false;
253 }
254
256
257 return BKE_image_has_ibuf(ima, &iuser);
258}
259
261{
262 /* Do not run 'replace' on packed images, it does not give user expected results at all. */
263 Image *ima = image_from_context(C);
264 return (ima && BLI_listbase_is_empty(&ima->packedfiles));
265}
266
267static void image_view_all(SpaceImage *sima, ARegion *region, wmOperator *op)
268{
269 float aspx, aspy, zoomx, zoomy, w, h;
270 int width, height;
271 const bool fit_view = RNA_boolean_get(op->ptr, "fit_view");
272
273 ED_space_image_get_size(sima, &width, &height);
274 ED_space_image_get_aspect(sima, &aspx, &aspy);
275
276 w = width * aspx;
277 h = height * aspy;
278
279 float xof = 0.0f, yof = 0.0f;
280 if ((sima->image == nullptr) || (sima->image->source == IMA_SRC_TILED)) {
281 /* Extend the shown area to cover all UDIM tiles. */
282 int x_tiles, y_tiles;
283 if (sima->image == nullptr) {
284 x_tiles = sima->tile_grid_shape[0];
285 y_tiles = sima->tile_grid_shape[1];
286 }
287 else {
288 x_tiles = y_tiles = 1;
290 int tile_x = (tile->tile_number - 1001) % 10;
291 int tile_y = (tile->tile_number - 1001) / 10;
292 x_tiles = max_ii(x_tiles, tile_x + 1);
293 y_tiles = max_ii(y_tiles, tile_y + 1);
294 }
295 }
296 xof = 0.5f * (x_tiles - 1.0f) * w;
297 yof = 0.5f * (y_tiles - 1.0f) * h;
298 w *= x_tiles;
299 h *= y_tiles;
300 }
301
302 /* check if the image will fit in the image with (zoom == 1) */
303 width = BLI_rcti_size_x(&region->winrct) + 1;
304 height = BLI_rcti_size_y(&region->winrct) + 1;
305
306 if (fit_view) {
307 const int margin = 5; /* margin from border */
308
309 zoomx = float(width) / (w + 2 * margin);
310 zoomy = float(height) / (h + 2 * margin);
311
312 sima_zoom_set(sima, region, min_ff(zoomx, zoomy), nullptr, false);
313 }
314 else {
315 if ((w >= width || h >= height) && (width > 0 && height > 0)) {
316 zoomx = float(width) / w;
317 zoomy = float(height) / h;
318
319 /* find the zoom value that will fit the image in the image space */
320 sima_zoom_set(sima, region, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), nullptr, false);
321 }
322 else {
323 sima_zoom_set(sima, region, 1.0f, nullptr, false);
324 }
325 }
326
327 sima->xof = xof;
328 sima->yof = yof;
329}
330
332{
334 // ARegion *region = CTX_wm_region(C); /* XXX. */
335
336 if (sima) {
337 return true; /* XXX (region && region->runtime->type->regionid == RGN_TYPE_WINDOW); */
338 }
339 return false;
340}
341
344{
346
347 if (sima && (CTX_data_edit_object(C) == nullptr)) {
348 return true;
349 }
350
351 return false;
352}
353
355
356/* -------------------------------------------------------------------- */
359
360namespace {
361
362struct ViewPanData {
363 float x, y;
364 float xof, yof;
365 int launch_event;
366 bool own_cursor;
367};
368
369} // namespace
370
371static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
372{
373 wmWindow *win = CTX_wm_window(C);
375 ViewPanData *vpd;
376
377 op->customdata = vpd = MEM_callocN<ViewPanData>("ImageViewPanData");
378
379 /* Grab will be set when running from gizmo. */
380 vpd->own_cursor = (win->grabcursor == 0);
381 if (vpd->own_cursor) {
383 }
384
385 vpd->x = event->xy[0];
386 vpd->y = event->xy[1];
387 vpd->xof = sima->xof;
388 vpd->yof = sima->yof;
389 vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
390
392}
393
394static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
395{
397 ViewPanData *vpd = static_cast<ViewPanData *>(op->customdata);
398
399 if (cancel) {
400 sima->xof = vpd->xof;
401 sima->yof = vpd->yof;
403 }
404
405 if (vpd->own_cursor) {
407 }
408 MEM_freeN(vpd);
409}
410
412{
414 float offset[2];
415
416 RNA_float_get_array(op->ptr, "offset", offset);
417 sima->xof += offset[0];
418 sima->yof += offset[1];
419
421
422 return OPERATOR_FINISHED;
423}
424
426{
427 if (event->type == MOUSEPAN) {
429 float offset[2];
430
431 offset[0] = (event->prev_xy[0] - event->xy[0]) / sima->zoom;
432 offset[1] = (event->prev_xy[1] - event->xy[1]) / sima->zoom;
433 RNA_float_set_array(op->ptr, "offset", offset);
434
436 return OPERATOR_FINISHED;
437 }
438
439 image_view_pan_init(C, op, event);
441}
442
444{
446 ViewPanData *vpd = static_cast<ViewPanData *>(op->customdata);
447 float offset[2];
448
449 switch (event->type) {
450 case MOUSEMOVE:
451 sima->xof = vpd->xof;
452 sima->yof = vpd->yof;
453 offset[0] = (vpd->x - event->xy[0]) / sima->zoom;
454 offset[1] = (vpd->y - event->xy[1]) / sima->zoom;
455 RNA_float_set_array(op->ptr, "offset", offset);
457 break;
458 default:
459 if (event->type == vpd->launch_event && event->val == KM_RELEASE) {
460 image_view_pan_exit(C, op, false);
461 return OPERATOR_FINISHED;
462 }
463 break;
464 }
465
467}
468
470{
471 image_view_pan_exit(C, op, true);
472}
473
475{
476 /* identifiers */
477 ot->name = "Pan View";
478 ot->idname = "IMAGE_OT_view_pan";
479 ot->description = "Pan the view";
480
481 /* API callbacks. */
482 ot->exec = image_view_pan_exec;
483 ot->invoke = image_view_pan_invoke;
484 ot->modal = image_view_pan_modal;
485 ot->cancel = image_view_pan_cancel;
487
488 /* flags */
490
491 /* properties */
493 "offset",
494 2,
495 nullptr,
496 -FLT_MAX,
497 FLT_MAX,
498 "Offset",
499 "Offset in floating-point units, 1.0 is the width and height of the image",
500 -FLT_MAX,
501 FLT_MAX);
502}
503
505
506/* -------------------------------------------------------------------- */
509
510namespace {
511
512struct ViewZoomData {
513 float origx, origy;
514 float zoom;
515 int launch_event;
516 float location[2];
517
518 /* needed for continuous zoom */
519 wmTimer *timer;
520 double timer_lastdraw;
521 bool own_cursor;
522
523 /* */
524 SpaceImage *sima;
525 ARegion *region;
526};
527
528} // namespace
529
530static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
531{
532 wmWindow *win = CTX_wm_window(C);
534 ARegion *region = CTX_wm_region(C);
535 ViewZoomData *vpd;
536
537 op->customdata = vpd = MEM_callocN<ViewZoomData>("ImageViewZoomData");
538
539 /* Grab will be set when running from gizmo. */
540 vpd->own_cursor = (win->grabcursor == 0);
541 if (vpd->own_cursor) {
543 }
544
545 vpd->origx = event->xy[0];
546 vpd->origy = event->xy[1];
547 vpd->zoom = sima->zoom;
548 vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
549
551 &region->v2d, event->mval[0], event->mval[1], &vpd->location[0], &vpd->location[1]);
552
553 if (U.viewzoom == USER_ZOOM_CONTINUE) {
554 /* needs a timer to continue redrawing */
555 vpd->timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
556 vpd->timer_lastdraw = BLI_time_now_seconds();
557 }
558
559 vpd->sima = sima;
560 vpd->region = region;
561
563}
564
565static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
566{
568 ViewZoomData *vpd = static_cast<ViewZoomData *>(op->customdata);
569
570 if (cancel) {
571 sima->zoom = vpd->zoom;
573 }
574
575 if (vpd->timer) {
576 WM_event_timer_remove(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
577 }
578
579 if (vpd->own_cursor) {
581 }
582 MEM_freeN(vpd);
583}
584
586{
588 ARegion *region = CTX_wm_region(C);
589
590 sima_zoom_set_factor(sima, region, RNA_float_get(op->ptr, "factor"), nullptr, false);
591
592 ED_region_tag_redraw(region);
593
594 return OPERATOR_FINISHED;
595}
596
597enum {
601};
602
604{
605 if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
607 ARegion *region = CTX_wm_region(C);
608 float delta, factor, location[2];
609
611 &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
612
613 delta = event->prev_xy[0] - event->xy[0] + event->prev_xy[1] - event->xy[1];
614
615 if (U.uiflag & USER_ZOOM_INVERT) {
616 delta *= -1;
617 }
618
619 factor = 1.0f + delta / 300.0f;
620 RNA_float_set(op->ptr, "factor", factor);
621 const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
622 sima_zoom_set(sima,
623 region,
624 sima->zoom * factor,
625 location,
626 (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
627 ED_region_tag_redraw(region);
628
629 return OPERATOR_FINISHED;
630 }
631
632 image_view_zoom_init(C, op, event);
634}
635
636static void image_zoom_apply(ViewZoomData *vpd,
637 wmOperator *op,
638 const int x,
639 const int y,
640 const short viewzoom,
641 const short zoom_invert,
642 const bool zoom_to_pos)
643{
644 float factor;
645 float delta;
646
647 if (viewzoom != USER_ZOOM_SCALE) {
648 if (U.uiflag & USER_ZOOM_HORIZ) {
649 delta = float(x - vpd->origx);
650 }
651 else {
652 delta = float(y - vpd->origy);
653 }
654 }
655 else {
656 delta = x - vpd->origx + y - vpd->origy;
657 }
658
659 delta /= U.pixelsize;
660
661 if (zoom_invert) {
662 delta = -delta;
663 }
664
665 if (viewzoom == USER_ZOOM_CONTINUE) {
666 double time = BLI_time_now_seconds();
667 float time_step = float(time - vpd->timer_lastdraw);
668 float zfac;
669 zfac = 1.0f + ((delta / 20.0f) * time_step);
670 vpd->timer_lastdraw = time;
671 /* this is the final zoom, but instead make it into a factor */
672 factor = (vpd->sima->zoom * zfac) / vpd->zoom;
673 }
674 else {
675 factor = 1.0f + delta / 300.0f;
676 }
677
678 RNA_float_set(op->ptr, "factor", factor);
679 sima_zoom_set(vpd->sima, vpd->region, vpd->zoom * factor, vpd->location, zoom_to_pos);
680 ED_region_tag_redraw(vpd->region);
681}
682
684{
685 ViewZoomData *vpd = static_cast<ViewZoomData *>(op->customdata);
686 short event_code = VIEW_PASS;
688
689 /* Execute the events. */
690 if (event->type == MOUSEMOVE) {
691 event_code = VIEW_APPLY;
692 }
693 else if (event->type == TIMER) {
694 /* Continuous zoom. */
695 if (event->customdata == vpd->timer) {
696 event_code = VIEW_APPLY;
697 }
698 }
699 else if (event->type == vpd->launch_event) {
700 if (event->val == KM_RELEASE) {
701 event_code = VIEW_CONFIRM;
702 }
703 }
704
705 switch (event_code) {
706 case VIEW_APPLY: {
707 const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
709 op,
710 event->xy[0],
711 event->xy[1],
712 U.viewzoom,
713 (U.uiflag & USER_ZOOM_INVERT) != 0,
714 (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
715 break;
716 }
717 case VIEW_CONFIRM: {
719 break;
720 }
721 }
722
723 if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
724 image_view_zoom_exit(C, op, false);
725 }
726
727 return ret;
728}
729
731{
732 image_view_zoom_exit(C, op, true);
733}
734
736{
737 PropertyRNA *prop;
738
739 /* identifiers */
740 ot->name = "Zoom View";
741 ot->idname = "IMAGE_OT_view_zoom";
742 ot->description = "Zoom in/out the image";
743
744 /* API callbacks. */
745 ot->exec = image_view_zoom_exec;
746 ot->invoke = image_view_zoom_invoke;
747 ot->modal = image_view_zoom_modal;
748 ot->cancel = image_view_zoom_cancel;
750
751 /* flags */
753
754 /* properties */
755 prop = RNA_def_float(ot->srna,
756 "factor",
757 0.0f,
758 -FLT_MAX,
759 FLT_MAX,
760 "Factor",
761 "Zoom factor, values higher than 1.0 zoom in, lower values zoom out",
762 -FLT_MAX,
763 FLT_MAX);
765
767}
768
770
771#ifdef WITH_INPUT_NDOF
772
773/* -------------------------------------------------------------------- */
776
777/* Combined pan/zoom from a 3D mouse device.
778 * Z zooms, XY pans
779 * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
780 * that explains the negative signs in the code below
781 */
782
783static wmOperatorStatus image_view_ndof_invoke(bContext *C,
784 wmOperator * /*op*/,
785 const wmEvent *event)
786{
787 if (event->type != NDOF_MOTION) {
788 return OPERATOR_CANCELLED;
789 }
790
792 ARegion *region = CTX_wm_region(C);
793
794 const wmNDOFMotionData &ndof = *static_cast<const wmNDOFMotionData *>(event->customdata);
795 const float pan_speed = NDOF_PIXELS_PER_SECOND;
796
797 blender::float3 pan_vec = ndof.dt * WM_event_ndof_translation_get_for_navigation(ndof);
798
799 mul_v2_fl(pan_vec, pan_speed / sima->zoom);
800
801 sima_zoom_set_factor(sima, region, max_ff(0.0f, 1.0f - pan_vec[2]), nullptr, false);
802 sima->xof += pan_vec[0];
803 sima->yof += pan_vec[1];
804
805 ED_region_tag_redraw(region);
806
807 return OPERATOR_FINISHED;
808}
809
810void IMAGE_OT_view_ndof(wmOperatorType *ot)
811{
812 /* identifiers */
813 ot->name = "NDOF Pan/Zoom";
814 ot->idname = "IMAGE_OT_view_ndof";
815 ot->description = "Use a 3D mouse device to pan/zoom the view";
816
817 /* API callbacks. */
818 ot->invoke = image_view_ndof_invoke;
820
821 /* flags */
822 ot->flag = OPTYPE_LOCK_BYPASS;
823}
824
826
827#endif /* WITH_INPUT_NDOF */
828
829/* -------------------------------------------------------------------- */
832
833/* Updates the fields of the View2D member of the SpaceImage struct.
834 * Default behavior is to reset the position of the image and set the zoom to 1
835 * If the image will not fit within the window rectangle, the zoom is adjusted */
836
838{
839 SpaceImage *sima;
840 ARegion *region;
841
842 /* retrieve state */
843 sima = CTX_wm_space_image(C);
844 region = CTX_wm_region(C);
845
846 image_view_all(sima, region, op);
847
848 ED_region_tag_redraw(region);
849
850 return OPERATOR_FINISHED;
851}
852
854{
855 PropertyRNA *prop;
856
857 /* identifiers */
858 ot->name = "Frame All";
859 ot->idname = "IMAGE_OT_view_all";
860 ot->description = "View the entire image";
861
862 /* API callbacks. */
863 ot->exec = image_view_all_exec;
865
866 /* flags */
867 ot->flag = OPTYPE_LOCK_BYPASS;
868
869 /* properties */
870 prop = RNA_def_boolean(ot->srna, "fit_view", false, "Fit View", "Fit frame to the viewport");
872}
873
875
876/* -------------------------------------------------------------------- */
879
881{
882 SpaceImage *sima;
883 ARegion *region;
884
885 sima = CTX_wm_space_image(C);
886 region = CTX_wm_region(C);
887
888 image_view_all(sima, region, op);
889
890 sima->cursor[0] = 0.5f;
891 sima->cursor[1] = 0.5f;
892
893 /* Needed for updating the cursor. */
895
896 return OPERATOR_FINISHED;
897}
898
900{
901 PropertyRNA *prop;
902
903 /* identifiers */
904 ot->name = "Cursor To Center View";
905 ot->description = "Set 2D Cursor To Center View location";
906 ot->idname = "IMAGE_OT_view_cursor_center";
907
908 /* API callbacks. */
911
912 /* properties */
913 prop = RNA_def_boolean(ot->srna, "fit_view", false, "Fit View", "Fit frame to the viewport");
915}
916
918
919/* -------------------------------------------------------------------- */
922
924{
926 ARegion *region = CTX_wm_region(C);
927
928 ED_image_view_center_to_point(sima, sima->cursor[0], sima->cursor[1]);
929
930 ED_region_tag_redraw(region);
931
932 return OPERATOR_FINISHED;
933}
934
936{
937 /* identifiers */
938 ot->name = "Center View to Cursor";
939 ot->description = "Center the view so that the cursor is in the middle of the view";
940 ot->idname = "IMAGE_OT_view_center_cursor";
941
942 /* API callbacks. */
945}
946
948
949/* -------------------------------------------------------------------- */
952
954{
955 SpaceImage *sima;
956 ARegion *region;
957 Scene *scene;
958 ViewLayer *view_layer;
959 Object *obedit;
960
961 /* retrieve state */
962 sima = CTX_wm_space_image(C);
963 region = CTX_wm_region(C);
964 scene = CTX_data_scene(C);
965 view_layer = CTX_data_view_layer(C);
966 obedit = CTX_data_edit_object(C);
967
968 /* get bounds */
969 float min[2], max[2];
970 if (ED_space_image_show_uvedit(sima, obedit)) {
972 scene, view_layer, nullptr);
973 bool success = ED_uvedit_minmax_multi(scene, objects, min, max);
974 if (!success) {
975 return OPERATOR_CANCELLED;
976 }
977 }
978 else if (ED_space_image_check_show_maskedit(sima, obedit)) {
979 if (!ED_mask_selected_minmax(C, min, max, false)) {
980 return OPERATOR_CANCELLED;
981 }
982 BKE_mask_coord_to_image(sima->image, &sima->iuser, min, min);
983 BKE_mask_coord_to_image(sima->image, &sima->iuser, max, max);
984 }
985 rctf bounds{};
986 bounds.xmin = min[0];
987 bounds.ymin = min[1];
988 bounds.xmax = max[0];
989 bounds.ymax = max[1];
990
991 /* add some margin */
992 BLI_rctf_scale(&bounds, 1.4f);
993
994 sima_zoom_set_from_bounds(sima, region, &bounds);
995
996 ED_region_tag_redraw(region);
997
998 return OPERATOR_FINISHED;
999}
1000
1005
1007{
1008 /* identifiers */
1009 ot->name = "View Center";
1010 ot->idname = "IMAGE_OT_view_selected";
1011 ot->description = "View all selected UVs";
1012
1013 /* API callbacks. */
1016}
1017
1019
1020/* -------------------------------------------------------------------- */
1023
1025{
1027 ARegion *region = CTX_wm_region(C);
1028 float location[2];
1029
1030 RNA_float_get_array(op->ptr, "location", location);
1031
1033 sima, region, powf(2.0f, 1.0f / 3.0f), location, U.uiflag & USER_ZOOM_TO_MOUSEPOS);
1034
1035 ED_region_tag_redraw(region);
1036
1037 return OPERATOR_FINISHED;
1038}
1039
1041 wmOperator *op,
1042 const wmEvent *event)
1043{
1044 ARegion *region = CTX_wm_region(C);
1045 float location[2];
1046
1048 &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
1049 RNA_float_set_array(op->ptr, "location", location);
1050
1051 return image_view_zoom_in_exec(C, op);
1052}
1053
1055{
1056 PropertyRNA *prop;
1057
1058 /* identifiers */
1059 ot->name = "Zoom In";
1060 ot->idname = "IMAGE_OT_view_zoom_in";
1061 ot->description = "Zoom in the image (centered around 2D cursor)";
1062
1063 /* API callbacks. */
1064 ot->invoke = image_view_zoom_in_invoke;
1067
1068 /* flags */
1069 ot->flag = OPTYPE_LOCK_BYPASS;
1070
1071 /* properties */
1072 prop = RNA_def_float_vector(ot->srna,
1073 "location",
1074 2,
1075 nullptr,
1076 -FLT_MAX,
1077 FLT_MAX,
1078 "Location",
1079 "Cursor location in screen coordinates",
1080 -10.0f,
1081 10.0f);
1083}
1084
1086{
1088 ARegion *region = CTX_wm_region(C);
1089 float location[2];
1090
1091 RNA_float_get_array(op->ptr, "location", location);
1092
1094 sima, region, powf(0.5f, 1.0f / 3.0f), location, U.uiflag & USER_ZOOM_TO_MOUSEPOS);
1095
1096 ED_region_tag_redraw(region);
1097
1098 return OPERATOR_FINISHED;
1099}
1100
1102 wmOperator *op,
1103 const wmEvent *event)
1104{
1105 ARegion *region = CTX_wm_region(C);
1106 float location[2];
1107
1109 &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
1110 RNA_float_set_array(op->ptr, "location", location);
1111
1112 return image_view_zoom_out_exec(C, op);
1113}
1114
1116{
1117 PropertyRNA *prop;
1118
1119 /* identifiers */
1120 ot->name = "Zoom Out";
1121 ot->idname = "IMAGE_OT_view_zoom_out";
1122 ot->description = "Zoom out the image (centered around 2D cursor)";
1123
1124 /* API callbacks. */
1128
1129 /* flags */
1130 ot->flag = OPTYPE_LOCK_BYPASS;
1131
1132 /* properties */
1133 prop = RNA_def_float_vector(ot->srna,
1134 "location",
1135 2,
1136 nullptr,
1137 -FLT_MAX,
1138 FLT_MAX,
1139 "Location",
1140 "Cursor location in screen coordinates",
1141 -10.0f,
1142 10.0f);
1144}
1145
1147
1148/* -------------------------------------------------------------------- */
1151
1153{
1155 ARegion *region = CTX_wm_region(C);
1156
1157 sima_zoom_set(sima, region, RNA_float_get(op->ptr, "ratio"), nullptr, false);
1158
1159 /* ensure pixel exact locations for draw */
1160 sima->xof = int(sima->xof);
1161 sima->yof = int(sima->yof);
1162
1163 ED_region_tag_redraw(region);
1164
1165 return OPERATOR_FINISHED;
1166}
1167
1169{
1170 /* identifiers */
1171 ot->name = "View Zoom Ratio";
1172 ot->idname = "IMAGE_OT_view_zoom_ratio";
1173 ot->description = "Set zoom ratio of the view";
1174
1175 /* API callbacks. */
1178
1179 /* flags */
1180 ot->flag = OPTYPE_LOCK_BYPASS;
1181
1182 /* properties */
1183 RNA_def_float(ot->srna,
1184 "ratio",
1185 0.0f,
1186 -FLT_MAX,
1187 FLT_MAX,
1188 "Ratio",
1189 "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out",
1190 -FLT_MAX,
1191 FLT_MAX);
1192}
1193
1195
1196/* -------------------------------------------------------------------- */
1199
1201{
1203 ARegion *region = CTX_wm_region(C);
1204 rctf bounds;
1205 const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
1206
1208
1210
1211 struct {
1212 float xof;
1213 float yof;
1214 float zoom;
1215 } sima_view_prev{};
1216 sima_view_prev.xof = sima->xof;
1217 sima_view_prev.yof = sima->yof;
1218 sima_view_prev.zoom = sima->zoom;
1219
1220 sima_zoom_set_from_bounds(sima, region, &bounds);
1221
1222 /* zoom out */
1223 if (!zoom_in) {
1224 sima->xof = sima_view_prev.xof + (sima->xof - sima_view_prev.xof);
1225 sima->yof = sima_view_prev.yof + (sima->yof - sima_view_prev.yof);
1226 sima->zoom = sima_view_prev.zoom * (sima_view_prev.zoom / sima->zoom);
1227 }
1228
1229 ED_region_tag_redraw(region);
1230
1231 return OPERATOR_FINISHED;
1232}
1233
1235{
1236 /* identifiers */
1237 ot->name = "Zoom to Border";
1238 ot->description = "Zoom in the view to the nearest item contained in the border";
1239 ot->idname = "IMAGE_OT_view_zoom_border";
1240
1241 /* API callbacks. */
1242 ot->invoke = WM_gesture_box_invoke;
1244 ot->modal = WM_gesture_box_modal;
1245 ot->cancel = WM_gesture_box_cancel;
1246
1248
1249 /* rna */
1251}
1252
1253/* load/replace/save callbacks */
1254static void image_filesel(bContext *C, wmOperator *op, const char *path)
1255{
1256 RNA_string_set(op->ptr, "filepath", path);
1258}
1259
1261
1262/* -------------------------------------------------------------------- */
1265
1271
1273{
1274 ImageOpenData *iod;
1275 op->customdata = iod = MEM_new<ImageOpenData>(__func__);
1276 iod->iuser = static_cast<ImageUser *>(
1277 CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data);
1279}
1280
1281static void image_open_cancel(bContext * /*C*/, wmOperator *op)
1282{
1283 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1284 op->customdata = nullptr;
1285 MEM_delete(iod);
1286}
1287
1289 Library *owner_library,
1290 wmOperator *op,
1291 const ImageFrameRange *range,
1292 const bool use_multiview)
1293{
1294 bool exists = false;
1295 Image *ima = nullptr;
1296
1297 errno = 0;
1298 ima = BKE_image_load_exists_in_lib(bmain, owner_library, range->filepath, &exists);
1299
1300 if (!ima) {
1301 if (op->customdata) {
1302 MEM_delete(static_cast<ImageOpenData *>(op->customdata));
1303 }
1304 BKE_reportf(op->reports,
1305 RPT_ERROR,
1306 "Cannot read '%s': %s",
1307 range->filepath,
1308 errno ? strerror(errno) : RPT_("unsupported image format"));
1309 return nullptr;
1310 }
1311
1312 /* If image already exists, update its file path based on relative path property, see: #109561.
1313 */
1314 if (exists) {
1315 STRNCPY(ima->filepath, range->filepath);
1316 return ima;
1317 }
1318
1319 /* handle multiview images */
1320 if (use_multiview) {
1321 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1322 ImageFormatData *imf = &iod->im_format;
1323
1324 ima->flag |= IMA_USE_VIEWS;
1325 ima->views_format = imf->views_format;
1326 *ima->stereo3d_format = imf->stereo3d_format;
1327 }
1328 else {
1329 ima->flag &= ~IMA_USE_VIEWS;
1331 }
1332
1333 if (ima->source == IMA_SRC_FILE) {
1334 if (range->udims_detected && range->udim_tiles.first) {
1335 ima->source = IMA_SRC_TILED;
1336 ImageTile *first_tile = static_cast<ImageTile *>(ima->tiles.first);
1337 first_tile->tile_number = range->offset;
1338 LISTBASE_FOREACH (LinkData *, node, &range->udim_tiles) {
1339 BKE_image_add_tile(ima, POINTER_AS_INT(node->data), nullptr);
1340 }
1341 }
1342 else if (range->length > 1) {
1343 ima->source = IMA_SRC_SEQUENCE;
1344 }
1345 }
1346
1347 return ima;
1348}
1349
1351{
1352 Main *bmain = CTX_data_main(C);
1353 ScrArea *area = CTX_wm_area(C);
1354 Scene *scene = CTX_data_scene(C);
1355 ImageUser *iuser = nullptr;
1356 Image *ima = nullptr;
1357 int frame_seq_len = 0;
1358 int frame_ofs = 1;
1359
1360 const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
1361 const bool use_udim = RNA_boolean_get(op->ptr, "use_udim_detecting");
1362
1363 if (!op->customdata) {
1364 image_open_init(C, op);
1365 }
1366
1367 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1368 ID *owner_id = iod->pprop.ptr.owner_id;
1369 Library *owner_library = owner_id ? owner_id->lib : nullptr;
1370 blender::StringRefNull root_path = owner_library ? owner_library->runtime->filepath_abs :
1372
1373 ListBase ranges = ED_image_filesel_detect_sequences(root_path, op, use_udim);
1374 LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) {
1375 Image *ima_range = image_open_single(bmain, owner_library, op, range, use_multiview);
1376
1377 /* take the first image */
1378 if ((ima == nullptr) && ima_range) {
1379 ima = ima_range;
1380 frame_seq_len = range->length;
1381 frame_ofs = range->offset;
1382 }
1383
1384 BLI_freelistN(&range->udim_tiles);
1385 }
1386 BLI_freelistN(&ranges);
1387
1388 if (ima == nullptr) {
1389 return OPERATOR_CANCELLED;
1390 }
1391
1392 /* hook into UI */
1393 if (iod->pprop.prop) {
1394 /* when creating new ID blocks, use is already 1, but RNA
1395 * pointer use also increases user, so this compensates it */
1396 id_us_min(&ima->id);
1397
1398 if (iod->pprop.ptr.owner_id) {
1399 BKE_id_move_to_same_lib(*bmain, ima->id, *iod->pprop.ptr.owner_id);
1400 }
1401
1402 PointerRNA imaptr = RNA_id_pointer_create(&ima->id);
1403 RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr, nullptr);
1404 RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
1405 }
1406
1407 if (iod->iuser) {
1408 iuser = iod->iuser;
1409 }
1410 else if (area && area->spacetype == SPACE_IMAGE) {
1411 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
1412 ED_space_image_set(bmain, sima, ima, false);
1413 iuser = &sima->iuser;
1414 }
1415 else {
1416 Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
1417 if (tex && tex->type == TEX_IMAGE) {
1418 iuser = &tex->iuser;
1419 }
1420
1421 if (iuser == nullptr) {
1422 Camera *cam = static_cast<Camera *>(
1423 CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data);
1424 if (cam) {
1425 LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
1426 if (bgpic->ima == ima) {
1427 iuser = &bgpic->iuser;
1428 break;
1429 }
1430 }
1431 }
1432 }
1433 }
1434
1435 /* initialize because of new image */
1436 if (iuser) {
1437 /* If the sequence was a tiled image, we only have one frame. */
1438 iuser->frames = (ima->source == IMA_SRC_SEQUENCE) ? frame_seq_len : 1;
1439 iuser->sfra = 1;
1440 iuser->framenr = 1;
1441 if (ima->source == IMA_SRC_MOVIE) {
1442 iuser->offset = 0;
1443 }
1444 else {
1445 iuser->offset = frame_ofs - 1;
1446 }
1447 iuser->scene = scene;
1448 BKE_image_init_imageuser(ima, iuser);
1449 }
1450
1451 /* XXX BKE_packedfile_unpack_image frees image buffers */
1453
1454 BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
1456
1457 op->customdata = nullptr;
1458 MEM_delete(iod);
1459
1460 return OPERATOR_FINISHED;
1461}
1462
1464{
1465 SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1466 const char *path = U.textudir;
1467 Image *ima = nullptr;
1468 Scene *scene = CTX_data_scene(C);
1469
1470 if (sima) {
1471 ima = sima->image;
1472 }
1473
1474 if (ima == nullptr) {
1475 Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
1476 if (tex && tex->type == TEX_IMAGE) {
1477 ima = tex->ima;
1478 }
1479 }
1480
1481 if (ima == nullptr) {
1483 PropertyRNA *prop;
1484
1485 /* hook into UI */
1487
1488 if (prop) {
1489 PointerRNA oldptr;
1490 Image *oldima;
1491
1492 oldptr = RNA_property_pointer_get(&ptr, prop);
1493 oldima = (Image *)oldptr.owner_id;
1494 /* unlikely to fail but better avoid strange crash */
1495 if (oldima && GS(oldima->id.name) == ID_IM) {
1496 ima = oldima;
1497 }
1498 }
1499 }
1500
1501 if (ima) {
1502 path = ima->filepath;
1503 }
1504
1505 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1506 return image_open_exec(C, op);
1507 }
1508
1509 image_open_init(C, op);
1510
1511 /* Show multi-view save options only if scene has multi-views. */
1512 PropertyRNA *prop;
1513 prop = RNA_struct_find_property(op->ptr, "show_multiview");
1514 RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
1515
1516 image_filesel(C, op, path);
1517
1519}
1520
1522 PropertyRNA *prop,
1523 void * /*user_data*/)
1524{
1525 const char *prop_id = RNA_property_identifier(prop);
1526
1527 return !STR_ELEM(prop_id, "filepath", "directory", "filename");
1528}
1529
1530static void image_open_draw(bContext * /*C*/, wmOperator *op)
1531{
1532 uiLayout *layout = op->layout;
1533 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1534 ImageFormatData *imf = &iod->im_format;
1535
1536 /* main draw call */
1537 uiDefAutoButsRNA(layout,
1538 op->ptr,
1540 nullptr,
1541 nullptr,
1543 false);
1544
1545 /* image template */
1546 PointerRNA imf_ptr = RNA_pointer_create_discrete(nullptr, &RNA_ImageFormatSettings, imf);
1547
1548 /* multiview template */
1549 if (RNA_boolean_get(op->ptr, "show_multiview")) {
1550 uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1551 }
1552}
1553
1555{
1557 ot->srna, "allow_path_tokens", true, "", "Allow the path to contain substitution tokens");
1559}
1560
1562{
1563 /* identifiers */
1564 ot->name = "Open Image";
1565 ot->description = "Open image";
1566 ot->idname = "IMAGE_OT_open";
1567
1568 /* API callbacks. */
1569 ot->exec = image_open_exec;
1570 ot->invoke = image_open_invoke;
1571 ot->cancel = image_open_cancel;
1572 ot->ui = image_open_draw;
1573
1574 /* flags */
1575 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1576
1577 /* properties */
1587
1589 ot->srna,
1590 "use_sequence_detection",
1591 true,
1592 "Detect Sequences",
1593 "Automatically detect animated sequences in selected images (based on file names)");
1594 RNA_def_boolean(ot->srna,
1595 "use_udim_detecting",
1596 true,
1597 "Detect UDIMs",
1598 "Detect selected UDIM files and load all matching tiles");
1599}
1600
1602
1603/* -------------------------------------------------------------------- */
1606
1608{
1609 Image *ima = static_cast<Image *>(op->customdata);
1610 if (ima == nullptr) {
1611 return OPERATOR_CANCELLED;
1612 }
1613
1614 char filepath[FILE_MAX];
1615 RNA_string_get(op->ptr, "filepath", filepath);
1616 if (BLI_path_is_rel(filepath)) {
1617 /* Relative path created by the file-browser are always relative to the current blendfile, need
1618 * to be made relative to the library blendfile path in case image is an editable linked data.
1619 */
1621 /* TODO: make this a BKE_lib_id helper (already a static function in BKE_image too), we likely
1622 * need this in more places in the future. ~~mont29 */
1623 BLI_path_rel(filepath,
1624 ID_IS_LINKED(&ima->id) ? ima->id.lib->runtime->filepath_abs :
1626 }
1627
1628 /* If loading into a tiled texture, ensure that the filename is tokenized. */
1629 if (ima->source == IMA_SRC_TILED) {
1630 BKE_image_ensure_tile_token(filepath, sizeof(filepath));
1631 }
1632
1633 PropertyRNA *imaprop;
1634 PointerRNA imaptr = RNA_id_pointer_create(&ima->id);
1635 imaprop = RNA_struct_find_property(&imaptr, "filepath");
1636
1637 RNA_property_string_set(&imaptr, imaprop, filepath);
1638 RNA_property_update(C, &imaptr, imaprop);
1639
1640 return OPERATOR_FINISHED;
1641}
1642
1644{
1645 Image *ima = image_from_context(C);
1646 if (!ima) {
1647 return OPERATOR_CANCELLED;
1648 }
1649
1650 char filepath[FILE_MAX];
1651 STRNCPY(filepath, ima->filepath);
1652 BLI_path_abs(filepath,
1653 ID_IS_LINKED(&ima->id) ? ima->id.lib->runtime->filepath_abs :
1655
1656 /* Shift+Click to open the file, Alt+Click to browse a folder in the OS's browser. */
1657 if (event->modifier & (KM_SHIFT | KM_ALT)) {
1658 wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
1659 PointerRNA props_ptr;
1660
1661 if (event->modifier & KM_ALT) {
1662 char *lslash = (char *)BLI_path_slash_rfind(filepath);
1663 if (lslash) {
1664 *lslash = '\0';
1665 }
1666 }
1667 else if (ima->source == IMA_SRC_TILED) {
1669 BKE_image_user_file_path(&iuser, ima, filepath);
1670 }
1671
1673 RNA_string_set(&props_ptr, "filepath", filepath);
1674 WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr, nullptr);
1675 WM_operator_properties_free(&props_ptr);
1676
1677 return OPERATOR_CANCELLED;
1678 }
1679
1680 /* The image is typically passed to the operator via layout/button context (e.g.
1681 * #uiLayoutSetContextPointer()). The File Browser doesn't support restoring this context
1682 * when calling `exec()` though, so we have to pass it the image via custom data. */
1683 op->customdata = ima;
1684
1685 image_filesel(C, op, filepath);
1686
1688}
1689
1691{
1692 Image *ima = image_from_context(C);
1693 return (ima && ID_IS_EDITABLE(ima));
1694}
1695
1697{
1698 /* identifiers */
1699 ot->name = "Browse Image";
1700 ot->description =
1701 "Open an image file browser, hold Shift to open the file, Alt to browse containing "
1702 "directory";
1703 ot->idname = "IMAGE_OT_file_browse";
1704
1705 /* API callbacks. */
1706 ot->exec = image_file_browse_exec;
1707 ot->invoke = image_file_browse_invoke;
1708 ot->poll = image_file_browse_poll;
1709
1710 /* flags */
1711 ot->flag = OPTYPE_UNDO;
1712
1713 /* properties */
1721}
1722
1724
1725/* -------------------------------------------------------------------- */
1728
1730{
1731 Scene *scene = CTX_data_scene(C);
1732 Image *ima = image_from_context(C);
1734
1735 if (!ima || !iuser) {
1736 /* Try to get a Texture, or a SpaceImage from context... */
1737 Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
1738 if (tex && tex->type == TEX_IMAGE) {
1739 ima = tex->ima;
1740 iuser = &tex->iuser;
1741 }
1742 }
1743
1744 if (!ima || !iuser || !BKE_image_has_anim(ima)) {
1745 return OPERATOR_CANCELLED;
1746 }
1747
1748 MovieReader *anim = ((ImageAnim *)ima->anims.first)->anim;
1749 if (!anim) {
1750 return OPERATOR_CANCELLED;
1751 }
1753 BKE_image_user_frame_calc(ima, iuser, scene->r.cfra);
1754
1755 return OPERATOR_FINISHED;
1756}
1757
1759{
1760 /* identifiers */
1761 ot->name = "Match Movie Length";
1762 ot->description = "Set image's user's length to the one of this video";
1763 ot->idname = "IMAGE_OT_match_movie_length";
1764
1765 /* API callbacks. */
1766 ot->exec = image_match_len_exec;
1767
1768 /* flags */
1769 /* Don't think we need undo for that. */
1770 ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
1771}
1772
1774
1775/* -------------------------------------------------------------------- */
1778
1780{
1781 Main *bmain = CTX_data_main(C);
1783 char filepath[FILE_MAX];
1784
1785 if (!sima->image) {
1786 return OPERATOR_CANCELLED;
1787 }
1788
1789 RNA_string_get(op->ptr, "filepath", filepath);
1790
1791 /* we can't do much if the filepath is longer than FILE_MAX :/ */
1792 STRNCPY(sima->image->filepath, filepath);
1793
1794 if (sima->image->source == IMA_SRC_GENERATED) {
1795 sima->image->source = IMA_SRC_FILE;
1796 BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_SRC_CHANGE);
1797 }
1798
1800 sima->image->source = IMA_SRC_MOVIE;
1801 }
1802 else {
1803 sima->image->source = IMA_SRC_FILE;
1804 }
1805
1806 /* XXX BKE_packedfile_unpack_image frees image buffers */
1808
1810 BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1811 DEG_id_tag_update(&sima->image->id, 0);
1813
1814 return OPERATOR_FINISHED;
1815}
1816
1818 wmOperator *op,
1819 const wmEvent * /*event*/)
1820{
1822
1823 if (!sima->image) {
1824 return OPERATOR_CANCELLED;
1825 }
1826
1827 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1828 return image_replace_exec(C, op);
1829 }
1830
1831 if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
1832 RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->filepath));
1833 }
1834
1835 image_filesel(C, op, sima->image->filepath);
1836
1838}
1839
1841{
1842 /* identifiers */
1843 ot->name = "Replace Image";
1844 ot->idname = "IMAGE_OT_replace";
1845 ot->description = "Replace current image by another one from disk";
1846
1847 /* API callbacks. */
1848 ot->exec = image_replace_exec;
1849 ot->invoke = image_replace_invoke;
1850 ot->poll = image_not_packed_poll;
1851
1852 /* flags */
1853 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1854
1855 /* properties */
1863}
1864
1866
1867/* -------------------------------------------------------------------- */
1870
1876
1878{
1879 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1880 RNA_string_get(op->ptr, "filepath", opts->filepath);
1882 }
1883
1884 opts->relative = (RNA_struct_find_property(op->ptr, "relative_path") &&
1885 RNA_boolean_get(op->ptr, "relative_path"));
1886 opts->save_copy = (RNA_struct_find_property(op->ptr, "copy") &&
1887 RNA_boolean_get(op->ptr, "copy"));
1888 opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
1889 RNA_boolean_get(op->ptr, "save_as_render"));
1890}
1891
1892static bool save_image_op(
1893 Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, const ImageSaveOptions *opts)
1894{
1895 WM_cursor_wait(true);
1896
1897 bool ok = BKE_image_save(op->reports, bmain, ima, iuser, opts);
1898
1899 WM_cursor_wait(false);
1900
1901 /* Remember file path for next save. */
1902 STRNCPY(G.filepath_last_image, opts->filepath);
1903
1905
1906 return ok;
1907}
1908
1910{
1911 Main *bmain = CTX_data_main(C);
1912 Image *image = image_from_context(C);
1914 Scene *scene = CTX_data_scene(C);
1915
1917 isd->image = image;
1918 isd->iuser = iuser;
1919
1920 if (!BKE_image_save_options_init(&isd->opts, bmain, scene, image, iuser, true, false)) {
1922 MEM_freeN(isd);
1923 return nullptr;
1924 }
1925
1926 isd->opts.do_newpath = true;
1927
1928 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
1929 RNA_string_set(op->ptr, "filepath", isd->opts.filepath);
1930 }
1931
1932 /* Enable save_copy by default for render results. */
1933 if (image->source == IMA_SRC_VIEWER && !RNA_struct_property_is_set(op->ptr, "copy")) {
1934 RNA_boolean_set(op->ptr, "copy", true);
1935 }
1936
1937 if (!RNA_struct_property_is_set(op->ptr, "save_as_render")) {
1938 RNA_boolean_set(op->ptr, "save_as_render", isd->opts.save_as_render);
1939 }
1940
1941 /* Show multi-view save options only if image has multi-views. */
1942 PropertyRNA *prop;
1943 prop = RNA_struct_find_property(op->ptr, "show_multiview");
1945 prop = RNA_struct_find_property(op->ptr, "use_multiview");
1947
1948 op->customdata = isd;
1949
1950 return isd;
1951}
1952
1954{
1955 if (op->customdata) {
1956 ImageSaveData *isd = static_cast<ImageSaveData *>(op->customdata);
1958
1959 MEM_freeN(isd);
1960 op->customdata = nullptr;
1961 }
1962}
1963
1965{
1966 Main *bmain = CTX_data_main(C);
1967 ImageSaveData *isd;
1968
1969 if (op->customdata) {
1970 isd = static_cast<ImageSaveData *>(op->customdata);
1971 }
1972 else {
1973 isd = image_save_as_init(C, op);
1974 if (isd == nullptr) {
1975 return OPERATOR_CANCELLED;
1976 }
1977 }
1978
1979 image_save_options_from_op(bmain, &isd->opts, op);
1981
1982 save_image_op(bmain, isd->image, isd->iuser, op, &isd->opts);
1983
1984 if (isd->opts.save_copy == false) {
1986 }
1987
1989
1990 return OPERATOR_FINISHED;
1991}
1992
1994{
1995 Main *bmain = CTX_data_main(C);
1996 ImageSaveData *isd = static_cast<ImageSaveData *>(op->customdata);
1997
1998 image_save_options_from_op(bmain, &isd->opts, op);
2000
2002}
2003
2005 wmOperator *op,
2006 const wmEvent * /*event*/)
2007{
2008 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
2009 return image_save_as_exec(C, op);
2010 }
2011
2013 if (isd == nullptr) {
2014 return OPERATOR_CANCELLED;
2015 }
2016
2017 image_filesel(C, op, isd->opts.filepath);
2018
2020}
2021
2023{
2025}
2026
2027static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *user_data)
2028{
2029 ImageSaveData *isd = static_cast<ImageSaveData *>(user_data);
2030 const char *prop_id = RNA_property_identifier(prop);
2031
2032 return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
2033 STREQ(prop_id, "filename") ||
2034 /* when saving a copy, relative path has no effect */
2035 (STREQ(prop_id, "relative_path") && RNA_boolean_get(ptr, "copy")) ||
2036 (STREQ(prop_id, "save_as_render") && isd->image->source == IMA_SRC_VIEWER));
2037}
2038
2039static void image_save_as_draw(bContext * /*C*/, wmOperator *op)
2040{
2041 uiLayout *layout = op->layout;
2042 ImageSaveData *isd = static_cast<ImageSaveData *>(op->customdata);
2043 const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
2044 const bool save_as_render = RNA_boolean_get(op->ptr, "save_as_render");
2045
2046 uiLayoutSetPropSep(layout, true);
2047 uiLayoutSetPropDecorate(layout, false);
2048
2049 /* Operator settings. */
2050 uiDefAutoButsRNA(layout,
2051 op->ptr,
2053 isd,
2054 nullptr,
2056 false);
2057
2058 layout->separator();
2059
2060 /* Image format settings. */
2062 nullptr, &RNA_ImageFormatSettings, &isd->opts.im_format);
2063 uiTemplateImageSettings(layout, &imf_ptr, save_as_render);
2064
2065 if (!save_as_render) {
2066 PointerRNA linear_settings_ptr = RNA_pointer_get(&imf_ptr, "linear_colorspace_settings");
2067 uiLayout *col = &layout->column(true);
2068 col->separator();
2069 col->prop(&linear_settings_ptr, "name", UI_ITEM_NONE, IFACE_("Color Space"), ICON_NONE);
2070 }
2071
2072 /* Multiview settings. */
2073 if (is_multiview) {
2074 uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
2075 }
2076}
2077
2079{
2081 return false;
2082 }
2083
2084 if (G.is_rendering) {
2085 /* no need to nullptr check here */
2086 Image *ima = image_from_context(C);
2087
2088 if (ima->source == IMA_SRC_VIEWER) {
2089 CTX_wm_operator_poll_msg_set(C, "can't save image while rendering");
2090 return false;
2091 }
2092 }
2093
2094 return true;
2095}
2096
2098{
2099 /* identifiers */
2100 ot->name = "Save As Image";
2101 ot->idname = "IMAGE_OT_save_as";
2102 ot->description = "Save the image with another name and/or settings";
2103
2104 /* API callbacks. */
2105 ot->exec = image_save_as_exec;
2106 ot->check = image_save_as_check;
2107 ot->invoke = image_save_as_invoke;
2108 ot->cancel = image_save_as_cancel;
2109 ot->ui = image_save_as_draw;
2110 ot->poll = image_save_as_poll;
2111
2112 /* flags */
2113 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2114
2115 /* properties */
2116 PropertyRNA *prop;
2117 prop = RNA_def_boolean(
2118 ot->srna,
2119 "save_as_render",
2120 false,
2121 "Save As Render",
2122 "Save image with render color management.\n"
2123 "For display image formats like PNG, apply view and display transform.\n"
2124 "For intermediate image formats like OpenEXR, use the default render output color space");
2126 prop = RNA_def_boolean(ot->srna,
2127 "copy",
2128 false,
2129 "Copy",
2130 "Create a new image file without modifying the current image in Blender");
2132
2137 FILE_SAVE,
2141}
2142
2144
2145/* -------------------------------------------------------------------- */
2148
2153{
2154 void *lock;
2155 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
2156 bool ret = false;
2157
2158 if (ibuf && BKE_image_buffer_format_writable(ibuf)) {
2159 ret = true;
2160 }
2161
2162 BKE_image_release_ibuf(ima, ibuf, lock);
2163 return ret;
2164}
2165
2167{
2168 /* Can't save if there are no pixels. */
2169 if (image_from_context_has_data_poll(C) == false) {
2170 return false;
2171 }
2172
2173 /* Check if there is a valid file path and image format we can write
2174 * outside of the 'poll' so we can show a report with a pop-up. */
2175
2176 /* Can always repack images.
2177 * Images without a filepath will go to "Save As". */
2178 return true;
2179}
2180
2182{
2183 Main *bmain = CTX_data_main(C);
2184 Image *image = image_from_context(C);
2186 Scene *scene = CTX_data_scene(C);
2187 ImageSaveOptions opts;
2188 bool ok = false;
2189
2190 if (BKE_image_has_packedfile(image)) {
2191 /* Save packed files to memory. */
2192 BKE_image_memorypack(image);
2193 /* Report since this can be called from key shortcuts. */
2194 BKE_reportf(op->reports, RPT_INFO, "Packed to memory image \"%s\"", image->filepath);
2195 return OPERATOR_FINISHED;
2196 }
2197
2198 if (!BKE_image_save_options_init(&opts, bmain, scene, image, iuser, false, false)) {
2200 return OPERATOR_CANCELLED;
2201 }
2202 image_save_options_from_op(bmain, &opts, op);
2203
2204 /* Check if file write permission is ok. */
2205 if (BLI_exists(opts.filepath) && !BLI_file_is_writable(opts.filepath)) {
2207 op->reports, RPT_ERROR, "Cannot save image, path \"%s\" is not writable", opts.filepath);
2208 }
2209 else if (save_image_op(bmain, image, iuser, op, &opts)) {
2210 /* Report since this can be called from key shortcuts. */
2211 BKE_reportf(op->reports, RPT_INFO, "Saved image \"%s\"", opts.filepath);
2212 ok = true;
2213 }
2214
2216
2217 if (ok) {
2218 return OPERATOR_FINISHED;
2219 }
2220
2221 return OPERATOR_CANCELLED;
2222}
2223
2225{
2226 Image *ima = image_from_context(C);
2228
2229 /* Not writable formats or images without a file-path will go to "Save As". */
2230 if (!BKE_image_has_packedfile(ima) &&
2231 (!BKE_image_has_filepath(ima) || !image_file_format_writable(ima, iuser)))
2232 {
2233 WM_operator_name_call(C, "IMAGE_OT_save_as", WM_OP_INVOKE_DEFAULT, nullptr, event);
2234 return OPERATOR_CANCELLED;
2235 }
2236 return image_save_exec(C, op);
2237}
2238
2240{
2241 /* identifiers */
2242 ot->name = "Save Image";
2243 ot->idname = "IMAGE_OT_save";
2244 ot->description = "Save the image with current name and settings";
2245
2246 /* API callbacks. */
2247 ot->exec = image_save_exec;
2248 ot->invoke = image_save_invoke;
2249 ot->poll = image_save_poll;
2250
2251 /* flags */
2252 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2253}
2254
2256
2257/* -------------------------------------------------------------------- */
2260
2262{
2263 Image *image = image_from_context(C);
2264 ImBuf *ibuf, *first_ibuf = nullptr;
2265 int tot = 0;
2266 char di[FILE_MAX];
2267 MovieCacheIter *iter;
2268
2269 if (image == nullptr) {
2270 return OPERATOR_CANCELLED;
2271 }
2272
2273 if (image->source != IMA_SRC_SEQUENCE) {
2274 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
2275 return OPERATOR_CANCELLED;
2276 }
2277
2278 if (image->type == IMA_TYPE_MULTILAYER) {
2279 BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences");
2280 return OPERATOR_CANCELLED;
2281 }
2282
2283 /* get total dirty buffers and first dirty buffer which is used for menu */
2284 ibuf = nullptr;
2285 if (image->cache != nullptr) {
2286 iter = IMB_moviecacheIter_new(image->cache);
2287 while (!IMB_moviecacheIter_done(iter)) {
2288 ibuf = IMB_moviecacheIter_getImBuf(iter);
2289 if (ibuf != nullptr && ibuf->userflags & IB_BITMAPDIRTY) {
2290 if (first_ibuf == nullptr) {
2291 first_ibuf = ibuf;
2292 }
2293 tot++;
2294 }
2296 }
2298 }
2299
2300 if (tot == 0) {
2301 BKE_report(op->reports, RPT_WARNING, "No images have been changed");
2302 return OPERATOR_CANCELLED;
2303 }
2304
2305 /* get a filename for menu */
2306 BLI_path_split_dir_part(first_ibuf->filepath, di, sizeof(di));
2307 BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
2308
2309 iter = IMB_moviecacheIter_new(image->cache);
2310 while (!IMB_moviecacheIter_done(iter)) {
2311 ibuf = IMB_moviecacheIter_getImBuf(iter);
2312
2313 if (ibuf != nullptr && ibuf->userflags & IB_BITMAPDIRTY) {
2314 if (0 == IMB_save_image(ibuf, ibuf->filepath, IB_byte_data)) {
2315 BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
2316 break;
2317 }
2318
2319 BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->filepath);
2320 ibuf->userflags &= ~IB_BITMAPDIRTY;
2321 }
2322
2324 }
2326
2327 return OPERATOR_FINISHED;
2328}
2329
2331{
2332 /* identifiers */
2333 ot->name = "Save Sequence";
2334 ot->idname = "IMAGE_OT_save_sequence";
2335 ot->description = "Save a sequence of images";
2336
2337 /* API callbacks. */
2340
2341 /* flags */
2342 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2343}
2344
2346
2347/* -------------------------------------------------------------------- */
2350
2355
2356static bool image_should_be_saved(Image *ima, bool *r_is_format_writable)
2357{
2358 if (BKE_image_is_dirty_writable(ima, r_is_format_writable) &&
2360 {
2362 }
2363 return false;
2364}
2365
2367{
2368 return strchr(ima->filepath, '\\') || strchr(ima->filepath, '/');
2369}
2370
2372{
2373 /* Images without a filepath (implied with IMA_SRC_GENERATED) should
2374 * be packed during a save_all operation. */
2375 return (ima->source == IMA_SRC_GENERATED) ||
2376 (ima->source == IMA_SRC_TILED && !BKE_image_has_filepath(ima));
2377}
2378
2380{
2383
2384 uint modified_images_count = ED_image_save_all_modified_info(bmain, &reports);
2385 bool should_save = modified_images_count || !BLI_listbase_is_empty(&reports.list);
2386
2388
2389 return should_save;
2390}
2391
2393{
2394 blender::Set<std::string> unique_paths;
2395
2396 int num_saveable_images = 0;
2397
2398 for (Image *ima = static_cast<Image *>(bmain->images.first); ima;
2399 ima = static_cast<Image *>(ima->id.next))
2400 {
2401 bool is_format_writable;
2402
2403 if (image_should_be_saved(ima, &is_format_writable)) {
2405 if (ID_IS_EDITABLE(ima)) {
2406 num_saveable_images++;
2407 }
2408 else {
2411 "Packed library image can't be saved: \"%s\" from \"%s\"",
2412 ima->id.name + 2,
2413 ima->id.lib->filepath);
2414 }
2415 }
2416 else if (!is_format_writable) {
2419 "Image can't be saved, use a different file format: \"%s\"",
2420 ima->id.name + 2);
2421 }
2422 else {
2423 if (image_has_valid_path(ima)) {
2424 num_saveable_images++;
2425 if (unique_paths.contains_as(ima->filepath)) {
2428 "Multiple images can't be saved to an identical path: \"%s\"",
2429 ima->filepath);
2430 }
2431 else {
2432 unique_paths.add(ima->filepath);
2433 }
2434 }
2435 else {
2438 "Image can't be saved, no valid file path: \"%s\"",
2439 ima->filepath);
2440 }
2441 }
2442 }
2443 }
2444
2445 return num_saveable_images;
2446}
2447
2449{
2450 Main *bmain = CTX_data_main(C);
2451
2453
2454 bool ok = true;
2455
2456 for (Image *ima = static_cast<Image *>(bmain->images.first); ima;
2457 ima = static_cast<Image *>(ima->id.next))
2458 {
2459 bool is_format_writable;
2460
2461 if (image_should_be_saved(ima, &is_format_writable)) {
2464 }
2465 else if (is_format_writable) {
2466 if (image_has_valid_path(ima)) {
2467 ImageSaveOptions opts;
2468 Scene *scene = CTX_data_scene(C);
2469 if (BKE_image_save_options_init(&opts, bmain, scene, ima, nullptr, false, false)) {
2470 bool saved_successfully = BKE_image_save(reports, bmain, ima, nullptr, &opts);
2471 ok = ok && saved_successfully;
2472 }
2474 }
2475 }
2476 }
2477 }
2478 return ok;
2479}
2480
2482{
2483 int num_files = ED_image_save_all_modified_info(CTX_data_main(C), nullptr);
2484 return num_files > 0;
2485}
2486
2492
2494{
2495 /* identifiers */
2496 ot->name = "Save All Modified";
2497 ot->idname = "IMAGE_OT_save_all_modified";
2498 ot->description = "Save all modified images";
2499
2500 /* API callbacks. */
2503
2504 /* flags */
2505 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2506}
2507
2509
2510/* -------------------------------------------------------------------- */
2513
2515{
2516 Main *bmain = CTX_data_main(C);
2517 Image *ima = image_from_context(C);
2519
2520 if (!ima) {
2521 return OPERATOR_CANCELLED;
2522 }
2523
2524 /* XXX BKE_packedfile_unpack_image frees image buffers */
2526
2527 BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
2528 DEG_id_tag_update(&ima->id, 0);
2530
2532
2533 return OPERATOR_FINISHED;
2534}
2535
2537{
2538 /* identifiers */
2539 ot->name = "Reload Image";
2540 ot->idname = "IMAGE_OT_reload";
2541 ot->description = "Reload current image from disk";
2542
2543 /* API callbacks. */
2544 ot->exec = image_reload_exec;
2545
2546 /* flags */
2547 ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
2548}
2549
2551
2552/* -------------------------------------------------------------------- */
2555
2556#define IMA_DEF_NAME N_("Untitled")
2557
2558enum {
2562};
2563
2567
2569{
2570 if (op->customdata) {
2571 return static_cast<ImageNewData *>(op->customdata);
2572 }
2573
2574 ImageNewData *data = MEM_new<ImageNewData>(__func__);
2575 UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2576 op->customdata = data;
2577 return data;
2578}
2579
2581{
2582 if (op->customdata) {
2583 MEM_delete(static_cast<ImageNewData *>(op->customdata));
2584 }
2585}
2586
2588{
2589 SpaceImage *sima;
2590 Image *ima;
2591 Main *bmain;
2592 PropertyRNA *prop;
2593 char name_buffer[MAX_ID_NAME - 2];
2594 const char *name;
2595 float color[4];
2596 int width, height, floatbuf, gen_type, alpha;
2597 int stereo3d;
2598
2599 /* retrieve state */
2600 sima = CTX_wm_space_image(C);
2601 bmain = CTX_data_main(C);
2602
2603 prop = RNA_struct_find_property(op->ptr, "name");
2604 RNA_property_string_get(op->ptr, prop, name_buffer);
2605 if (!RNA_property_is_set(op->ptr, prop)) {
2606 /* Default value, we can translate! */
2607 name = DATA_(name_buffer);
2608 }
2609 else {
2610 name = name_buffer;
2611 }
2612 width = RNA_int_get(op->ptr, "width");
2613 height = RNA_int_get(op->ptr, "height");
2614 floatbuf = RNA_boolean_get(op->ptr, "float");
2615 gen_type = RNA_enum_get(op->ptr, "generated_type");
2616 RNA_float_get_array(op->ptr, "color", color);
2617 alpha = RNA_boolean_get(op->ptr, "alpha");
2618 stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
2619 bool tiled = RNA_boolean_get(op->ptr, "tiled");
2620
2621 if (!alpha) {
2622 color[3] = 1.0f;
2623 }
2624
2625 ima = BKE_image_add_generated(bmain,
2626 width,
2627 height,
2628 name,
2629 alpha ? 32 : 24,
2630 floatbuf,
2631 gen_type,
2632 color,
2633 stereo3d,
2634 false,
2635 tiled);
2636
2637 if (!ima) {
2638 image_new_free(op);
2639 return OPERATOR_CANCELLED;
2640 }
2641
2642 /* hook into UI */
2644
2645 if (data->pprop.prop) {
2646 /* when creating new ID blocks, use is already 1, but RNA
2647 * pointer use also increases user, so this compensates it */
2648 id_us_min(&ima->id);
2649
2650 if (data->pprop.ptr.owner_id) {
2651 BKE_id_move_to_same_lib(*bmain, ima->id, *data->pprop.ptr.owner_id);
2652 }
2653
2654 PointerRNA imaptr = RNA_id_pointer_create(&ima->id);
2655 RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr, nullptr);
2656 RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
2657 }
2658 else if (sima) {
2659 ED_space_image_set(bmain, sima, ima, false);
2660 }
2661 else {
2662 /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to
2663 * anything. ref. #94599. */
2664 id_us_min(&ima->id);
2665 }
2666
2667 BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : nullptr, IMA_SIGNAL_USER_NEW_IMAGE);
2668
2670
2671 image_new_free(op);
2672
2673 return OPERATOR_FINISHED;
2674}
2675
2677{
2678 /* Get property in advance, it doesn't work after WM_operator_props_dialog_popup. */
2680 op->customdata = data = MEM_new<ImageNewData>(__func__);
2681 UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2682
2683 /* Better for user feedback. */
2684 RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2686 C, op, 300, IFACE_("Create a New Image"), IFACE_("New Image"));
2687}
2688
2689static void image_new_draw(bContext * /*C*/, wmOperator *op)
2690{
2691 uiLayout *col;
2692 uiLayout *layout = op->layout;
2693#if 0
2694 Scene *scene = CTX_data_scene(C);
2695 const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2696#endif
2697
2698 /* copy of WM_operator_props_dialog_popup() layout */
2699
2700 uiLayoutSetPropSep(layout, true);
2701 uiLayoutSetPropDecorate(layout, false);
2702
2703 col = &layout->column(false);
2704 col->prop(op->ptr, "name", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2705 col->prop(op->ptr, "width", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2706 col->prop(op->ptr, "height", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2707 col->prop(op->ptr, "color", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2708 col->prop(op->ptr, "alpha", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2709 col->prop(op->ptr, "generated_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2710 col->prop(op->ptr, "float", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2711 col->prop(op->ptr, "tiled", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2712
2713#if 0
2714 if (is_multiview) {
2715 col[0].label("", ICON_NONE);
2716 col[1].prop( op->ptr, "use_stereo_3d", 0, std::nullopt, ICON_NONE);
2717 }
2718#endif
2719}
2720
2721static void image_new_cancel(bContext * /*C*/, wmOperator *op)
2722{
2723 image_new_free(op);
2724}
2725
2727{
2728 PropertyRNA *prop;
2729 static const float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2730
2731 /* identifiers */
2732 ot->name = "New Image";
2733 ot->description = "Create a new image";
2734 ot->idname = "IMAGE_OT_new";
2735
2736 /* API callbacks. */
2737 ot->exec = image_new_exec;
2738 ot->invoke = image_new_invoke;
2739 ot->ui = image_new_draw;
2740 ot->cancel = image_new_cancel;
2741
2742 /* flags */
2743 ot->flag = OPTYPE_UNDO;
2744
2745 /* properties */
2746 ot->prop = RNA_def_string(
2747 ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
2748 prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2750 prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2752 prop = RNA_def_float_color(
2753 ot->srna, "color", 4, nullptr, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2755 RNA_def_property_float_array_default(prop, default_color);
2756 RNA_def_boolean(ot->srna, "alpha", true, "Alpha", "Create an image with an alpha channel");
2757 RNA_def_enum(ot->srna,
2758 "generated_type",
2761 "Generated Type",
2762 "Fill the image with a grid for UV map testing");
2763 RNA_def_boolean(ot->srna,
2764 "float",
2765 false,
2766 "32-bit Float",
2767 "Create image with 32-bit floating-point bit depth");
2769 prop = RNA_def_boolean(
2770 ot->srna, "use_stereo_3d", false, "Stereo 3D", "Create an image with left and right views");
2772 prop = RNA_def_boolean(ot->srna, "tiled", false, "Tiled", "Create a tiled image");
2774}
2775
2776#undef IMA_DEF_NAME
2777
2779
2780/* -------------------------------------------------------------------- */
2783
2785{
2786 Image *ima = image_from_context(C);
2788 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
2790 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
2791
2792 if (ibuf == nullptr) {
2793 /* TODO: this should actually never happen, but does for render-results -> cleanup. */
2794 return OPERATOR_CANCELLED;
2795 }
2796
2797 const bool use_flip_x = RNA_boolean_get(op->ptr, "use_flip_x");
2798 const bool use_flip_y = RNA_boolean_get(op->ptr, "use_flip_y");
2799
2800 if (!use_flip_x && !use_flip_y) {
2801 BKE_image_release_ibuf(ima, ibuf, nullptr);
2802 return OPERATOR_FINISHED;
2803 }
2804
2805 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
2806
2807 if (is_paint) {
2809 }
2810
2811 const int size_x = ibuf->x;
2812 const int size_y = ibuf->y;
2813
2814 if (ibuf->float_buffer.data) {
2815 float *float_pixels = ibuf->float_buffer.data;
2816
2817 float *orig_float_pixels = static_cast<float *>(MEM_dupallocN(float_pixels));
2818 for (int x = 0; x < size_x; x++) {
2819 const int source_pixel_x = use_flip_x ? size_x - x - 1 : x;
2820 for (int y = 0; y < size_y; y++) {
2821 const int source_pixel_y = use_flip_y ? size_y - y - 1 : y;
2822
2823 const float *source_pixel =
2824 &orig_float_pixels[4 * (source_pixel_x + source_pixel_y * size_x)];
2825 float *target_pixel = &float_pixels[4 * (x + y * size_x)];
2826
2827 copy_v4_v4(target_pixel, source_pixel);
2828 }
2829 }
2830 MEM_freeN(orig_float_pixels);
2831
2832 if (ibuf->byte_buffer.data) {
2833 IMB_byte_from_float(ibuf);
2834 }
2835 }
2836 else if (ibuf->byte_buffer.data) {
2837 uchar *char_pixels = ibuf->byte_buffer.data;
2838 uchar *orig_char_pixels = static_cast<uchar *>(MEM_dupallocN(char_pixels));
2839 for (int x = 0; x < size_x; x++) {
2840 const int source_pixel_x = use_flip_x ? size_x - x - 1 : x;
2841 for (int y = 0; y < size_y; y++) {
2842 const int source_pixel_y = use_flip_y ? size_y - y - 1 : y;
2843
2844 const uchar *source_pixel =
2845 &orig_char_pixels[4 * (source_pixel_x + source_pixel_y * size_x)];
2846 uchar *target_pixel = &char_pixels[4 * (x + y * size_x)];
2847
2848 copy_v4_v4_uchar(target_pixel, source_pixel);
2849 }
2850 }
2851 MEM_freeN(orig_char_pixels);
2852 }
2853 else {
2854 BKE_image_release_ibuf(ima, ibuf, nullptr);
2855 return OPERATOR_CANCELLED;
2856 }
2857
2859 BKE_image_mark_dirty(ima, ibuf);
2860
2861 if (ibuf->mipmap[0]) {
2863 }
2864
2866
2868
2871
2872 BKE_image_release_ibuf(ima, ibuf, nullptr);
2873
2874 return OPERATOR_FINISHED;
2875}
2876
2878{
2879 /* identifiers */
2880 ot->name = "Flip Image";
2881 ot->idname = "IMAGE_OT_flip";
2882 ot->description = "Flip the image";
2883
2884 /* API callbacks. */
2885 ot->exec = image_flip_exec;
2887
2888 /* properties */
2889 PropertyRNA *prop;
2890 prop = RNA_def_boolean(
2891 ot->srna, "use_flip_x", false, "Horizontal", "Flip the image horizontally");
2893 prop = RNA_def_boolean(ot->srna, "use_flip_y", false, "Vertical", "Flip the image vertically");
2895
2896 /* flags */
2897 ot->flag = OPTYPE_REGISTER;
2898}
2899
2901
2902/* -------------------------------------------------------------------- */
2905
2907{
2908 Image *ima = image_from_context(C);
2910 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
2912 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
2913
2914 if (ibuf == nullptr) {
2915 /* TODO: this should actually never happen, but does for render-results -> cleanup. */
2916 return OPERATOR_CANCELLED;
2917 }
2918
2919 int degrees = RNA_enum_get(op->ptr, "degrees");
2920
2921 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
2922
2923 if (is_paint) {
2925 }
2926
2927 if (!IMB_rotate_orthogonal(ibuf, degrees)) {
2928 BKE_image_release_ibuf(ima, ibuf, nullptr);
2929 return OPERATOR_CANCELLED;
2930 }
2931
2933 BKE_image_mark_dirty(ima, ibuf);
2934
2935 if (ibuf->mipmap[0]) {
2937 }
2938
2940
2942
2944
2946 BKE_image_release_ibuf(ima, ibuf, nullptr);
2947
2948 return OPERATOR_FINISHED;
2949}
2950
2952{
2953 static const EnumPropertyItem orthogonal_rotation_items[] = {
2954 {90, "90", 0, "90 Degrees", "Rotate 90 degrees clockwise"},
2955 {180, "180", 0, "180 Degrees", "Rotate 180 degrees clockwise"},
2956 {270, "270", 0, "270 Degrees", "Rotate 270 degrees clockwise"},
2957 {0, nullptr, 0, nullptr, nullptr},
2958 };
2959
2960 /* identifiers */
2961 ot->name = "Rotate Image Orthogonal";
2962 ot->idname = "IMAGE_OT_rotate_orthogonal";
2963 ot->description = "Rotate the image";
2964
2965 /* API callbacks. */
2968
2969 /* properties */
2970 PropertyRNA *prop;
2971 prop = RNA_def_enum(ot->srna,
2972 "degrees",
2973 orthogonal_rotation_items,
2974 90,
2975 "Degrees",
2976 "Amount of rotation in degrees (90, 180, 270)");
2978
2979 /* flags */
2980 ot->flag = OPTYPE_REGISTER;
2981}
2982
2984
2985/* -------------------------------------------------------------------- */
2988
2990{
2991 Scene *scene = CTX_data_scene(C);
2992 Image *ima = image_from_context(C);
2993 if (ima == nullptr) {
2994 return OPERATOR_CANCELLED;
2995 }
2996
2997 if (G.is_rendering && ima->source == IMA_SRC_VIEWER) {
2998 BKE_report(op->reports, RPT_ERROR, "Images cannot be copied while rendering");
2999 return OPERATOR_CANCELLED;
3000 }
3001
3003 WM_cursor_wait(true);
3004 void *lock;
3005 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
3006 bool changed = false;
3007 if (ibuf) {
3008 /* Clipboard uses byte buffer, so match saving an 8 bit PNG for color management. */
3009 const bool save_as_render = ima->flag & IMA_VIEW_AS_RENDER;
3010
3011 ImageFormatData image_format;
3012 BKE_image_format_init_for_write(&image_format, scene, nullptr);
3013 BKE_image_format_set(&image_format, nullptr, R_IMF_IMTYPE_PNG);
3014 image_format.depth = R_IMF_CHAN_DEPTH_8;
3015
3016 ImBuf *colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
3017 ibuf, save_as_render, true, &image_format);
3018
3019 if (WM_clipboard_image_set_byte_buffer(colormanaged_ibuf)) {
3020 changed = true;
3021 }
3022
3023 if (colormanaged_ibuf != ibuf) {
3024 IMB_freeImBuf(colormanaged_ibuf);
3025 }
3026 BKE_image_format_free(&image_format);
3027 }
3028 BKE_image_release_ibuf(ima, ibuf, lock);
3029 WM_cursor_wait(false);
3030
3031 return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3032}
3033
3035{
3037 CTX_wm_operator_poll_msg_set(C, "No images available");
3038 return false;
3039 }
3040
3041 return true;
3042}
3043
3045{
3046 /* identifiers */
3047 ot->name = "Copy Image";
3048 ot->idname = "IMAGE_OT_clipboard_copy";
3049 ot->description = "Copy the image to the clipboard";
3050
3051 /* API callbacks. */
3054
3055 /* flags */
3056 ot->flag = OPTYPE_REGISTER;
3057}
3058
3060
3061/* -------------------------------------------------------------------- */
3064
3066{
3067 bool changed = false;
3068
3069 WM_cursor_wait(true);
3070 ImBuf *ibuf = WM_clipboard_image_get();
3071 if (ibuf) {
3072 ED_undo_push_op(C, op);
3073
3074 Main *bmain = CTX_data_main(C);
3076 Image *ima = BKE_image_add_from_imbuf(bmain, ibuf, "Clipboard");
3077 IMB_freeImBuf(ibuf);
3078
3079 ED_space_image_set(bmain, sima, ima, false);
3080 BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : nullptr, IMA_SIGNAL_USER_NEW_IMAGE);
3082 changed = true;
3083 }
3084 WM_cursor_wait(false);
3085
3086 return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3087}
3088
3090{
3092 if (!sima) {
3093 CTX_wm_operator_poll_msg_set(C, "Image Editor not found");
3094 return false;
3095 }
3096
3098 CTX_wm_operator_poll_msg_set(C, "No compatible images are on the clipboard");
3099 return false;
3100 }
3101
3102 return true;
3103}
3104
3106{
3107 /* identifiers */
3108 ot->name = "Paste Image";
3109 ot->idname = "IMAGE_OT_clipboard_paste";
3110 ot->description = "Paste new image from the clipboard";
3111
3112 /* API callbacks. */
3115
3116 /* flags */
3117 ot->flag = OPTYPE_REGISTER;
3118}
3119
3121
3122/* -------------------------------------------------------------------- */
3125
3127{
3128 Image *ima = image_from_context(C);
3130 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3132 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
3133
3134 /* flags indicate if this channel should be inverted */
3135 const bool r = RNA_boolean_get(op->ptr, "invert_r");
3136 const bool g = RNA_boolean_get(op->ptr, "invert_g");
3137 const bool b = RNA_boolean_get(op->ptr, "invert_b");
3138 const bool a = RNA_boolean_get(op->ptr, "invert_a");
3139
3140 size_t i;
3141
3142 if (ibuf == nullptr) {
3143 /* TODO: this should actually never happen, but does for render-results -> cleanup */
3144 return OPERATOR_CANCELLED;
3145 }
3146
3147 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
3148
3149 if (is_paint) {
3151 }
3152
3153 /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
3154 if (ibuf->float_buffer.data) {
3155
3156 float *fp = ibuf->float_buffer.data;
3157 for (i = size_t(ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
3158 if (r) {
3159 fp[0] = 1.0f - fp[0];
3160 }
3161 if (g) {
3162 fp[1] = 1.0f - fp[1];
3163 }
3164 if (b) {
3165 fp[2] = 1.0f - fp[2];
3166 }
3167 if (a) {
3168 fp[3] = 1.0f - fp[3];
3169 }
3170 }
3171
3172 if (ibuf->byte_buffer.data) {
3173 IMB_byte_from_float(ibuf);
3174 }
3175 }
3176 else if (ibuf->byte_buffer.data) {
3177
3178 uchar *cp = ibuf->byte_buffer.data;
3179 for (i = size_t(ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
3180 if (r) {
3181 cp[0] = 255 - cp[0];
3182 }
3183 if (g) {
3184 cp[1] = 255 - cp[1];
3185 }
3186 if (b) {
3187 cp[2] = 255 - cp[2];
3188 }
3189 if (a) {
3190 cp[3] = 255 - cp[3];
3191 }
3192 }
3193 }
3194 else {
3195 BKE_image_release_ibuf(ima, ibuf, nullptr);
3196 return OPERATOR_CANCELLED;
3197 }
3198
3200 BKE_image_mark_dirty(ima, ibuf);
3201
3202 if (ibuf->mipmap[0]) {
3204 }
3205
3207
3209
3211
3213
3214 BKE_image_release_ibuf(ima, ibuf, nullptr);
3215
3216 return OPERATOR_FINISHED;
3217}
3218
3220{
3221 PropertyRNA *prop;
3222
3223 /* identifiers */
3224 ot->name = "Invert Channels";
3225 ot->idname = "IMAGE_OT_invert";
3226 ot->description = "Invert image's channels";
3227
3228 /* API callbacks. */
3229 ot->exec = image_invert_exec;
3231
3232 /* properties */
3233 prop = RNA_def_boolean(ot->srna, "invert_r", false, "Red", "Invert red channel");
3235 prop = RNA_def_boolean(ot->srna, "invert_g", false, "Green", "Invert green channel");
3237 prop = RNA_def_boolean(ot->srna, "invert_b", false, "Blue", "Invert blue channel");
3239 prop = RNA_def_boolean(ot->srna, "invert_a", false, "Alpha", "Invert alpha channel");
3241
3242 /* flags */
3243 ot->flag = OPTYPE_REGISTER;
3244}
3245
3247
3248/* -------------------------------------------------------------------- */
3251
3253{
3254 Image *ima = image_from_context(C);
3256 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
3257 if (!RNA_property_is_set(op->ptr, prop)) {
3258 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3259 const int size[2] = {ibuf->x, ibuf->y};
3261 BKE_image_release_ibuf(ima, ibuf, nullptr);
3262 }
3264 C, op, 200, IFACE_("Scale Image to New Size"), IFACE_("Resize"));
3265}
3266
3268{
3269 Image *ima = image_from_context(C);
3272 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
3273
3274 if (is_paint) {
3276 }
3277
3278 const bool is_scaling_all = RNA_boolean_get(op->ptr, "all_udims");
3279
3280 if (!is_scaling_all) {
3281 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3282
3283 if (ibuf == nullptr) {
3284 /* TODO: this should actually never happen, but does for render-results -> cleanup */
3285 return OPERATOR_CANCELLED;
3286 }
3287
3288 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
3289 int size[2];
3290 if (RNA_property_is_set(op->ptr, prop)) {
3292 }
3293 else {
3294 size[0] = ibuf->x;
3295 size[1] = ibuf->y;
3297 }
3298
3299 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
3301 IMB_scale(ibuf, size[0], size[1], IMBScaleFilter::Box, false);
3302 BKE_image_mark_dirty(ima, ibuf);
3303 BKE_image_release_ibuf(ima, ibuf, nullptr);
3305 }
3306 else {
3307 // Ensure that an image buffer can be aquired for all UDIM tiles
3308 LISTBASE_FOREACH (ImageTile *, current_tile, &ima->tiles) {
3309 iuser.tile = current_tile->tile_number;
3310
3311 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3312
3313 if (ibuf == nullptr) {
3314 /* TODO: this should actually never happen, but does for render-results -> cleanup */
3315 return OPERATOR_CANCELLED;
3316 }
3317
3318 BKE_image_release_ibuf(ima, ibuf, nullptr);
3319 }
3320
3322 LISTBASE_FOREACH (ImageTile *, current_tile, &ima->tiles) {
3323 iuser.tile = current_tile->tile_number;
3324
3325 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3326
3327 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
3328 int size[2];
3329 if (RNA_property_is_set(op->ptr, prop)) {
3331 }
3332 else {
3333 size[0] = ibuf->x;
3334 size[1] = ibuf->y;
3336 }
3337
3339 IMB_scale(ibuf, size[0], size[1], IMBScaleFilter::Box, false);
3340 BKE_image_mark_dirty(ima, ibuf);
3341 BKE_image_release_ibuf(ima, ibuf, nullptr);
3342 }
3344 }
3345
3347
3348 DEG_id_tag_update(&ima->id, 0);
3350
3351 return OPERATOR_FINISHED;
3352}
3353
3355{
3356 /* identifiers */
3357 ot->name = "Resize Image";
3358 ot->idname = "IMAGE_OT_resize";
3359 ot->description = "Resize the image";
3360
3361 /* API callbacks. */
3362 ot->invoke = image_scale_invoke;
3363 ot->exec = image_scale_exec;
3365
3366 /* properties */
3367 RNA_def_int_vector(ot->srna, "size", 2, nullptr, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
3369 ot->srna, "all_udims", false, "All UDIM Tiles", "Scale all the image's UDIM tiles");
3370
3371 /* flags */
3372 ot->flag = OPTYPE_REGISTER;
3373}
3374
3376
3377/* -------------------------------------------------------------------- */
3380
3381static bool image_pack_test(Image *ima, const char **r_error_message)
3382{
3383 if (!ima) {
3384 return false;
3385 }
3386
3387 if (!ID_IS_EDITABLE(&ima->id)) {
3388 *r_error_message = "Image is not editable";
3389 return false;
3390 }
3391
3393 *r_error_message = "Movies or image sequences do not support packing";
3394 return false;
3395 }
3396
3397 return true;
3398}
3399
3401{
3402 Image *ima = image_from_context(C);
3403 const char *error_message = nullptr;
3404
3405 if (image_pack_test(ima, &error_message)) {
3406 return true;
3407 }
3408
3409 if (error_message) {
3410 CTX_wm_operator_poll_msg_set(C, error_message);
3411 }
3412 return false;
3413}
3414
3416{
3417 Main *bmain = CTX_data_main(C);
3418 Image *ima = image_from_context(C);
3419
3420 const char *error_message = nullptr;
3421 if (!image_pack_test(ima, &error_message)) {
3422 if (error_message) {
3423 BKE_report(op->reports, RPT_ERROR, error_message);
3424 }
3425 return OPERATOR_CANCELLED;
3426 }
3427
3428 if (BKE_image_is_dirty(ima)) {
3430 }
3431 else {
3432 BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
3433 }
3434
3436
3437 return OPERATOR_FINISHED;
3438}
3439
3441{
3442 /* identifiers */
3443 ot->name = "Pack Image";
3444 ot->description = "Pack an image as embedded data into the .blend file";
3445 ot->idname = "IMAGE_OT_pack";
3446
3447 /* API callbacks. */
3448 ot->exec = image_pack_exec;
3449 ot->poll = image_pack_poll;
3450
3451 /* flags */
3452 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3453}
3454
3456
3457/* -------------------------------------------------------------------- */
3460
3462{
3463 Main *bmain = CTX_data_main(C);
3464 Image *ima = image_from_context(C);
3465 int method = RNA_enum_get(op->ptr, "method");
3466
3467 /* find the supplied image by name */
3468 if (RNA_struct_property_is_set(op->ptr, "id")) {
3469 char imaname[MAX_ID_NAME - 2];
3470 RNA_string_get(op->ptr, "id", imaname);
3471 ima = static_cast<Image *>(BLI_findstring(&bmain->images, imaname, offsetof(ID, name) + 2));
3472 if (!ima) {
3473 ima = image_from_context(C);
3474 }
3475 }
3476
3477 if (!ima || !BKE_image_has_packedfile(ima)) {
3478 return OPERATOR_CANCELLED;
3479 }
3480
3481 if (!ID_IS_EDITABLE(&ima->id)) {
3482 BKE_report(op->reports, RPT_ERROR, "Image is not editable");
3483 return OPERATOR_CANCELLED;
3484 }
3485
3487 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
3488 return OPERATOR_CANCELLED;
3489 }
3490
3491 if (G.fileflags & G_FILE_AUTOPACK) {
3492 BKE_report(op->reports,
3494 "AutoPack is enabled, so image will be packed again on file save");
3495 }
3496
3497 /* XXX BKE_packedfile_unpack_image frees image buffers */
3499
3501
3503
3504 return OPERATOR_FINISHED;
3505}
3506
3508{
3509 Image *ima = image_from_context(C);
3510
3511 if (RNA_struct_property_is_set(op->ptr, "id")) {
3512 return image_unpack_exec(C, op);
3513 }
3514
3515 if (!ima || !BKE_image_has_packedfile(ima)) {
3516 return OPERATOR_CANCELLED;
3517 }
3518
3519 if (!ID_IS_EDITABLE(&ima->id)) {
3520 BKE_report(op->reports, RPT_ERROR, "Image is not editable");
3521 return OPERATOR_CANCELLED;
3522 }
3523
3525 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
3526 return OPERATOR_CANCELLED;
3527 }
3528
3529 if (G.fileflags & G_FILE_AUTOPACK) {
3530 BKE_report(op->reports,
3532 "AutoPack is enabled, so image will be packed again on file save");
3533 }
3534
3535 unpack_menu(C,
3536 "IMAGE_OT_unpack",
3537 ima->id.name + 2,
3538 ima->filepath,
3539 "textures",
3541 ((ImagePackedFile *)ima->packedfiles.first)->packedfile :
3542 nullptr);
3543
3544 return OPERATOR_FINISHED;
3545}
3546
3548{
3549 /* identifiers */
3550 ot->name = "Unpack Image";
3551 ot->description = "Save an image packed in the .blend file to disk";
3552 ot->idname = "IMAGE_OT_unpack";
3553
3554 /* API callbacks. */
3555 ot->exec = image_unpack_exec;
3556 ot->invoke = image_unpack_invoke;
3557 ot->poll = image_pack_poll;
3558
3559 /* flags */
3560 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3561
3562 /* properties */
3564 ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
3565 /* XXX, weak!, will fail with library, name collisions */
3567 ot->srna, "id", nullptr, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
3568}
3569
3571
3572/* -------------------------------------------------------------------- */
3575
3577 ARegion *region,
3578 const int mval[2],
3579 float r_fpos[2])
3580{
3581 void *lock;
3582 ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
3583
3584 if (ibuf == nullptr) {
3586 return false;
3587 }
3588
3589 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &r_fpos[0], &r_fpos[1]);
3590
3592 return true;
3593}
3594
3596 SpaceImage *sima, ARegion *region, const int mval[2], float r_col[3], bool *r_is_data)
3597{
3598 if (r_is_data) {
3599 *r_is_data = false;
3600 }
3601 if (sima->image == nullptr) {
3602 return false;
3603 }
3604 float uv[2];
3605 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &uv[0], &uv[1]);
3606 int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, nullptr);
3607
3608 void *lock;
3610 bool ret = false;
3611
3612 if (ibuf == nullptr) {
3614 return false;
3615 }
3616
3617 if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
3618 const float *fp;
3619 uchar *cp;
3620 int x = int(uv[0] * ibuf->x), y = int(uv[1] * ibuf->y);
3621
3622 CLAMP(x, 0, ibuf->x - 1);
3623 CLAMP(y, 0, ibuf->y - 1);
3624
3625 if (ibuf->float_buffer.data) {
3626 fp = (ibuf->float_buffer.data + (ibuf->channels) * (y * ibuf->x + x));
3627 copy_v3_v3(r_col, fp);
3628 ret = true;
3629 }
3630 else if (ibuf->byte_buffer.data) {
3631 cp = ibuf->byte_buffer.data + 4 * (y * ibuf->x + x);
3632 rgb_uchar_to_float(r_col, cp);
3634 ret = true;
3635 }
3636 }
3637
3638 if (r_is_data) {
3639 *r_is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
3640 }
3641
3643 return ret;
3644}
3645
3647{
3648 /* identifiers */
3649 ot->name = "Sample Color";
3650 ot->idname = "IMAGE_OT_sample";
3651 ot->description = "Use mouse to sample a color in current image";
3652
3653 /* API callbacks. */
3654 ot->invoke = ED_imbuf_sample_invoke;
3655 ot->modal = ED_imbuf_sample_modal;
3656 ot->cancel = ED_imbuf_sample_cancel;
3657 ot->poll = ED_imbuf_sample_poll;
3658
3659 /* flags */
3660 ot->flag = OPTYPE_BLOCKING;
3661
3662 PropertyRNA *prop;
3663 prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3666}
3667
3669
3670/* -------------------------------------------------------------------- */
3673
3675{
3677 ARegion *region = CTX_wm_region(C);
3678 Scene *scene = CTX_data_scene(C);
3679 Image *ima = ED_space_image(sima);
3680
3681 int x_start = RNA_int_get(op->ptr, "xstart");
3682 int y_start = RNA_int_get(op->ptr, "ystart");
3683 int x_end = RNA_int_get(op->ptr, "xend");
3684 int y_end = RNA_int_get(op->ptr, "yend");
3685
3686 float uv1[2], uv2[2], ofs[2];
3687 UI_view2d_region_to_view(&region->v2d, x_start, y_start, &uv1[0], &uv1[1]);
3688 UI_view2d_region_to_view(&region->v2d, x_end, y_end, &uv2[0], &uv2[1]);
3689
3690 /* If the image has tiles, shift the positions accordingly. */
3691 int tile = BKE_image_get_tile_from_pos(ima, uv1, uv1, ofs);
3692 sub_v2_v2(uv2, ofs);
3693
3694 void *lock;
3696 Histogram *hist = &sima->sample_line_hist;
3697
3698 if (ibuf == nullptr) {
3700 return OPERATOR_CANCELLED;
3701 }
3702 /* hmmmm */
3703 if (ibuf->channels < 3) {
3705 return OPERATOR_CANCELLED;
3706 }
3707
3708 copy_v2_v2(hist->co[0], uv1);
3709 copy_v2_v2(hist->co[1], uv2);
3710
3711 /* enable line drawing */
3712 hist->flag |= HISTO_FLAG_SAMPLELINE;
3713
3715
3716 /* reset y zoom */
3717 hist->ymax = 1.0f;
3718
3720
3722
3723 return OPERATOR_FINISHED;
3724}
3725
3727{
3729
3730 Histogram *hist = &sima->sample_line_hist;
3732
3733 if (!ED_space_image_has_buffer(sima)) {
3734 return OPERATOR_CANCELLED;
3735 }
3736
3737 return WM_gesture_straightline_invoke(C, op, event);
3738}
3739
3741{
3742 /* identifiers */
3743 ot->name = "Sample Line";
3744 ot->idname = "IMAGE_OT_sample_line";
3745 ot->description = "Sample a line and show it in Scope panels";
3746
3747 /* API callbacks. */
3748 ot->invoke = image_sample_line_invoke;
3750 ot->exec = image_sample_line_exec;
3753
3754 /* flags */
3755 ot->flag = 0; /* no undo/register since this operates on the space */
3756
3758}
3759
3761
3762/* -------------------------------------------------------------------- */
3765
3767{
3768 static const EnumPropertyItem point_items[] = {
3769 {0, "BLACK_POINT", 0, "Black Point", ""},
3770 {1, "WHITE_POINT", 0, "White Point", ""},
3771 {0, nullptr, 0, nullptr, nullptr},
3772 };
3773
3774 /* identifiers */
3775 ot->name = "Set Curves Point";
3776 ot->idname = "IMAGE_OT_curves_point_set";
3777 ot->description = "Set black point or white point for curves";
3778
3779 /* flags */
3780 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3781
3782 /* API callbacks. */
3783 ot->invoke = ED_imbuf_sample_invoke;
3784 ot->modal = ED_imbuf_sample_modal;
3785 ot->cancel = ED_imbuf_sample_cancel;
3787
3788 /* properties */
3790 ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
3791
3792 PropertyRNA *prop;
3793 prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3796}
3797
3799
3800/* -------------------------------------------------------------------- */
3803
3805{
3806 Image *ima = image_from_context(C);
3807
3808 return (ima && ima->type == IMA_TYPE_R_RESULT);
3809}
3810
3812{
3813 Image *ima = image_from_context(C);
3814 const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
3815
3816 if (!ED_image_slot_cycle(ima, direction)) {
3817 return OPERATOR_CANCELLED;
3818 }
3819
3821
3822 /* no undo push for browsing existing */
3824 if ((slot && slot->render) || ima->render_slot == ima->last_render_slot) {
3825 return OPERATOR_CANCELLED;
3826 }
3827
3828 return OPERATOR_FINISHED;
3829}
3830
3832{
3833 /* identifiers */
3834 ot->name = "Cycle Render Slot";
3835 ot->idname = "IMAGE_OT_cycle_render_slot";
3836 ot->description = "Cycle through all non-void render slots";
3837
3838 /* API callbacks. */
3841
3842 /* flags */
3843 ot->flag = OPTYPE_REGISTER;
3844
3845 RNA_def_boolean(ot->srna, "reverse", false, "Cycle in Reverse", "");
3846}
3847
3849
3850/* -------------------------------------------------------------------- */
3853
3855{
3856 Image *ima = image_from_context(C);
3858
3859 if (!BKE_image_clear_renderslot(ima, iuser, ima->render_slot)) {
3860 return OPERATOR_CANCELLED;
3861 }
3862
3864
3865 return OPERATOR_FINISHED;
3866}
3867
3869{
3870 /* identifiers */
3871 ot->name = "Clear Render Slot";
3872 ot->idname = "IMAGE_OT_clear_render_slot";
3873 ot->description = "Clear the currently selected render slot";
3874
3875 /* API callbacks. */
3878
3879 /* flags */
3880 ot->flag = OPTYPE_REGISTER;
3881}
3882
3884
3885/* -------------------------------------------------------------------- */
3888
3890{
3891 Image *ima = image_from_context(C);
3892
3893 RenderSlot *slot = BKE_image_add_renderslot(ima, nullptr);
3894 ima->render_slot = BLI_findindex(&ima->renderslots, slot);
3895
3897
3898 return OPERATOR_FINISHED;
3899}
3900
3902{
3903 /* identifiers */
3904 ot->name = "Add Render Slot";
3905 ot->idname = "IMAGE_OT_add_render_slot";
3906 ot->description = "Add a new render slot";
3907
3908 /* API callbacks. */
3911
3912 /* flags */
3913 ot->flag = OPTYPE_REGISTER;
3914}
3915
3917
3918/* -------------------------------------------------------------------- */
3921
3923{
3924 Image *ima = image_from_context(C);
3926
3927 if (!BKE_image_remove_renderslot(ima, iuser, ima->render_slot)) {
3928 return OPERATOR_CANCELLED;
3929 }
3930
3932
3933 return OPERATOR_FINISHED;
3934}
3935
3937{
3938 /* identifiers */
3939 ot->name = "Remove Render Slot";
3940 ot->idname = "IMAGE_OT_remove_render_slot";
3941 ot->description = "Remove the current render slot";
3942
3943 /* API callbacks. */
3946
3947 /* flags */
3948 ot->flag = OPTYPE_REGISTER;
3949}
3950
3952
3953/* -------------------------------------------------------------------- */
3956
3958{
3959 /* prevent changes during render */
3960 if (G.is_rendering) {
3961 return false;
3962 }
3963
3965}
3966
3968{
3969 Scene *scene = CTX_data_scene(C);
3970
3971 /* set the new frame number */
3972 scene->r.cfra = RNA_int_get(op->ptr, "frame");
3974 scene->r.subframe = 0.0f;
3975
3976 /* do updates */
3979}
3980
3982{
3983 change_frame_apply(C, op);
3984
3985 return OPERATOR_FINISHED;
3986}
3987
3988static int frame_from_event(bContext *C, const wmEvent *event)
3989{
3990 ARegion *region = CTX_wm_region(C);
3991 Scene *scene = CTX_data_scene(C);
3992 int framenr = 0;
3993
3994 if (region->regiontype == RGN_TYPE_WINDOW) {
3995 float sfra = scene->r.sfra, efra = scene->r.efra, framelen = region->winx / (efra - sfra + 1);
3996
3997 framenr = sfra + event->mval[0] / framelen;
3998 }
3999 else {
4000 float viewx, viewy;
4001
4002 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
4003
4004 framenr = round_fl_to_int(viewx);
4005 }
4006
4007 return framenr;
4008}
4009
4011{
4012 ARegion *region = CTX_wm_region(C);
4013
4014 if (region->regiontype == RGN_TYPE_WINDOW) {
4015 const SpaceImage *sima = CTX_wm_space_image(C);
4016 if (!ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
4017 return OPERATOR_PASS_THROUGH;
4018 }
4019 }
4020
4021 RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
4022
4023 change_frame_apply(C, op);
4024
4025 /* add temp handler */
4027
4029}
4030
4032{
4033 switch (event->type) {
4034 case EVT_ESCKEY:
4035 return OPERATOR_FINISHED;
4036
4037 case MOUSEMOVE:
4038 RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
4039 change_frame_apply(C, op);
4040 break;
4041
4042 case LEFTMOUSE:
4043 case RIGHTMOUSE:
4044 if (event->val == KM_RELEASE) {
4045 return OPERATOR_FINISHED;
4046 }
4047 break;
4048 default: {
4049 break;
4050 }
4051 }
4052
4054}
4055
4057{
4058 /* identifiers */
4059 ot->name = "Change Frame";
4060 ot->idname = "IMAGE_OT_change_frame";
4061 ot->description = "Interactively change the current frame number";
4062
4063 /* API callbacks. */
4064 ot->exec = change_frame_exec;
4065 ot->invoke = change_frame_invoke;
4066 ot->modal = change_frame_modal;
4067 ot->poll = change_frame_poll;
4068
4069 /* flags */
4070 ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
4071
4072 /* rna */
4073 RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
4074}
4075
4076/* Reload cached render results... */
4077/* goes over all scenes, reads render layers */
4079{
4080 Main *bmain = CTX_data_main(C);
4081 Scene *scene = CTX_data_scene(C);
4083 Image *ima;
4084
4085 ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
4086 if (sima->image == nullptr) {
4087 ED_space_image_set(bmain, sima, ima, false);
4088 }
4089
4090 RE_ReadRenderResult(scene, scene);
4091
4093 return OPERATOR_FINISHED;
4094}
4095
4097{
4098 ot->name = "Open Cached Render";
4099 ot->idname = "IMAGE_OT_read_viewlayers";
4100 ot->description = "Read all the current scene's view layers from cache, as needed";
4101
4104
4105 /* flags */
4106 ot->flag = 0;
4107}
4108
4110
4111/* -------------------------------------------------------------------- */
4114
4116{
4117 ARegion *region = CTX_wm_region(C);
4118 Scene *scene = CTX_data_scene(C);
4119 Render *re = RE_GetSceneRender(scene);
4121
4122 if (re == nullptr) {
4123 /* Shouldn't happen, but better be safe close to the release. */
4124 return OPERATOR_CANCELLED;
4125 }
4126
4127 /* Get information about the previous render, or current scene if no render yet. */
4128 int width, height;
4129 BKE_render_resolution(&scene->r, false, &width, &height);
4131 &scene->r;
4132
4133 /* Get rectangle from the operator. */
4134 rctf border;
4136 UI_view2d_region_to_view_rctf(&region->v2d, &border, &border);
4137
4138 /* Adjust for cropping. */
4139 if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
4140 border.xmin = rd->border.xmin + border.xmin * (rd->border.xmax - rd->border.xmin);
4141 border.xmax = rd->border.xmin + border.xmax * (rd->border.xmax - rd->border.xmin);
4142 border.ymin = rd->border.ymin + border.ymin * (rd->border.ymax - rd->border.ymin);
4143 border.ymax = rd->border.ymin + border.ymax * (rd->border.ymax - rd->border.ymin);
4144 }
4145
4146 CLAMP(border.xmin, 0.0f, 1.0f);
4147 CLAMP(border.ymin, 0.0f, 1.0f);
4148 CLAMP(border.xmax, 0.0f, 1.0f);
4149 CLAMP(border.ymax, 0.0f, 1.0f);
4150
4151 /* Drawing a border surrounding the entire camera view switches off border rendering
4152 * or the border covers no pixels. */
4153 if ((border.xmin <= 0.0f && border.xmax >= 1.0f && border.ymin <= 0.0f && border.ymax >= 1.0f) ||
4154 (border.xmin == border.xmax || border.ymin == border.ymax))
4155 {
4156 scene->r.mode &= ~R_BORDER;
4157 }
4158 else {
4159 /* Snap border to pixel boundaries, so drawing a border within a pixel selects that pixel. */
4160 border.xmin = floorf(border.xmin * width) / width;
4161 border.xmax = ceilf(border.xmax * width) / width;
4162 border.ymin = floorf(border.ymin * height) / height;
4163 border.ymax = ceilf(border.ymax * height) / height;
4164
4165 /* Set border. */
4166 scene->r.border = border;
4167 scene->r.mode |= R_BORDER;
4168 }
4169
4172
4173 return OPERATOR_FINISHED;
4174}
4175
4177{
4178 /* identifiers */
4179 ot->name = "Render Region";
4180 ot->description = "Set the boundaries of the render region and enable render region";
4181 ot->idname = "IMAGE_OT_render_border";
4182
4183 /* API callbacks. */
4184 ot->invoke = WM_gesture_box_invoke;
4185 ot->exec = render_border_exec;
4186 ot->modal = WM_gesture_box_modal;
4187 ot->cancel = WM_gesture_box_cancel;
4189
4190 /* flags */
4191 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4192
4193 /* rna */
4195}
4196
4198
4199/* -------------------------------------------------------------------- */
4202
4204{
4205 Scene *scene = CTX_data_scene(C);
4206 scene->r.mode &= ~R_BORDER;
4208 BLI_rctf_init(&scene->r.border, 0.0f, 1.0f, 0.0f, 1.0f);
4209 return OPERATOR_FINISHED;
4210}
4211
4213{
4214 /* identifiers */
4215 ot->name = "Clear Render Region";
4216 ot->description = "Clear the boundaries of the render region and disable render region";
4217 ot->idname = "IMAGE_OT_clear_render_border";
4218
4219 /* API callbacks. */
4222
4223 /* flags */
4224 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4225}
4226
4228
4229/* -------------------------------------------------------------------- */
4232
4234{
4235 RNA_float_get_array(ptr, "color", tile->gen_color);
4236 tile->gen_type = RNA_enum_get(ptr, "generated_type");
4237 tile->gen_x = RNA_int_get(ptr, "width");
4238 tile->gen_y = RNA_int_get(ptr, "height");
4239 bool is_float = RNA_boolean_get(ptr, "float");
4240
4241 tile->gen_flag = is_float ? IMA_GEN_FLOAT : 0;
4242 tile->gen_depth = RNA_boolean_get(ptr, "alpha") ? 32 : 24;
4243
4244 return BKE_image_fill_tile(ima, tile);
4245}
4246
4248{
4249 uiLayoutSetPropSep(layout, true);
4250 uiLayoutSetPropDecorate(layout, false);
4251
4252 uiLayout *col = &layout->column(false);
4253 col->prop(ptr, "color", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4254 col->prop(ptr, "width", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4255 col->prop(ptr, "height", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4256 col->prop(ptr, "alpha", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4257 col->prop(ptr, "generated_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4258 col->prop(ptr, "float", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4259}
4260
4262{
4263 ImageUser iuser;
4264 BKE_imageuser_default(&iuser);
4265 if (tile != nullptr) {
4266 iuser.tile = tile->tile_number;
4267 }
4268
4269 /* Acquire ibuf to get the default values.
4270 * If the specified tile has no ibuf, try acquiring the main tile instead
4271 * (unless the specified tile already was the first tile). */
4272 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
4273 if (ibuf == nullptr && (tile != nullptr) && (tile != ima->tiles.first)) {
4274 ibuf = BKE_image_acquire_ibuf(ima, nullptr, nullptr);
4275 }
4276
4277 if (ibuf != nullptr) {
4278 /* Initialize properties from reference tile. */
4279 RNA_int_set(ptr, "width", ibuf->x);
4280 RNA_int_set(ptr, "height", ibuf->y);
4281 RNA_boolean_set(ptr, "float", ibuf->float_buffer.data != nullptr);
4282 RNA_boolean_set(ptr, "alpha", ibuf->planes > 24);
4283
4284 BKE_image_release_ibuf(ima, ibuf, nullptr);
4285 }
4286}
4287
4289{
4290 PropertyRNA *prop;
4291 static const float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
4292 prop = RNA_def_float_color(
4293 srna, "color", 4, nullptr, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
4295 RNA_def_property_float_array_default(prop, default_color);
4296 RNA_def_enum(srna,
4297 "generated_type",
4300 "Generated Type",
4301 "Fill the image with a grid for UV map testing");
4302 prop = RNA_def_int(srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
4304 prop = RNA_def_int(srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
4306
4307 /* Only needed when filling the first tile. */
4309 srna, "float", false, "32-bit Float", "Create image with 32-bit floating-point bit depth");
4310 RNA_def_boolean(srna, "alpha", true, "Alpha", "Create an image with an alpha channel");
4311}
4312
4314{
4315 Image *ima = CTX_data_edit_image(C);
4316
4317 return (ima != nullptr && ima->source == IMA_SRC_TILED && BKE_image_has_ibuf(ima, nullptr));
4318}
4319
4321{
4322 Image *ima = CTX_data_edit_image(C);
4323
4324 int start_tile = RNA_int_get(op->ptr, "number");
4325 int end_tile = start_tile + RNA_int_get(op->ptr, "count") - 1;
4326
4327 if (start_tile < 1001 || end_tile > IMA_UDIM_MAX) {
4328 BKE_report(op->reports, RPT_ERROR, "Invalid UDIM index range was specified");
4329 return OPERATOR_CANCELLED;
4330 }
4331
4332 bool fill_tile = RNA_boolean_get(op->ptr, "fill");
4333 char *label = RNA_string_get_alloc(op->ptr, "label", nullptr, 0, nullptr);
4334
4335 /* BKE_image_add_tile assumes a pre-sorted list of tiles. */
4337
4338 ImageTile *last_tile_created = nullptr;
4339 for (int tile_number = start_tile; tile_number <= end_tile; tile_number++) {
4340 ImageTile *tile = BKE_image_add_tile(ima, tile_number, label);
4341
4342 if (tile != nullptr) {
4343 if (fill_tile) {
4344 do_fill_tile(op->ptr, ima, tile);
4345 }
4346
4347 last_tile_created = tile;
4348 }
4349 }
4350 MEM_freeN(label);
4351
4352 if (!last_tile_created) {
4353 BKE_report(op->reports, RPT_WARNING, "No UDIM tiles were created");
4354 return OPERATOR_CANCELLED;
4355 }
4356
4357 ima->active_tile_index = BLI_findindex(&ima->tiles, last_tile_created);
4358
4360 return OPERATOR_FINISHED;
4361}
4362
4364{
4365 Image *ima = CTX_data_edit_image(C);
4366
4367 /* Find the first gap in tile numbers or the number after the last if
4368 * no gap exists. */
4369 int next_number = 0;
4370 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
4371 next_number = tile->tile_number + 1;
4372 if (tile->next == nullptr || tile->next->tile_number > next_number) {
4373 break;
4374 }
4375 }
4376
4377 ImageTile *tile = static_cast<ImageTile *>(BLI_findlink(&ima->tiles, ima->active_tile_index));
4378 tile_fill_init(op->ptr, ima, tile);
4379
4380 RNA_int_set(op->ptr, "number", next_number);
4381 RNA_int_set(op->ptr, "count", 1);
4382 RNA_string_set(op->ptr, "label", "");
4383
4385 op,
4386 300,
4387 IFACE_("Add Tile to Image"),
4389}
4390
4391static void tile_add_draw(bContext * /*C*/, wmOperator *op)
4392{
4393 uiLayout *col;
4394 uiLayout *layout = op->layout;
4395
4396 uiLayoutSetPropSep(layout, true);
4397 uiLayoutSetPropDecorate(layout, false);
4398
4399 col = &layout->column(false);
4400 col->prop(op->ptr, "number", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4401 col->prop(op->ptr, "count", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4402 col->prop(op->ptr, "label", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4403 layout->prop(op->ptr, "fill", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4404
4405 if (RNA_boolean_get(op->ptr, "fill")) {
4406 draw_fill_tile(op->ptr, layout);
4407 }
4408}
4409
4411{
4412 PropertyRNA *prop;
4413
4414 /* identifiers */
4415 ot->name = "Add Tile";
4416 ot->description = "Adds a tile to the image";
4417 ot->idname = "IMAGE_OT_tile_add";
4418
4419 /* API callbacks. */
4420 ot->poll = tile_add_poll;
4421 ot->exec = tile_add_exec;
4422 ot->invoke = tile_add_invoke;
4423 ot->ui = tile_add_draw;
4424
4425 /* flags */
4426 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4427
4428 RNA_def_int(ot->srna,
4429 "number",
4430 1002,
4431 1001,
4433 "Number",
4434 "UDIM number of the tile",
4435 1001,
4436 1099);
4437 RNA_def_int(ot->srna, "count", 1, 1, INT_MAX, "Count", "How many tiles to add", 1, 1000);
4438 RNA_def_string(ot->srna, "label", nullptr, 0, "Label", "Optional tile label");
4439 prop = RNA_def_boolean(ot->srna, "fill", true, "Fill", "Fill new tile with a generated image");
4441 def_fill_tile(ot->srna);
4442}
4443
4445
4446/* -------------------------------------------------------------------- */
4449
4451{
4452 Image *ima = CTX_data_edit_image(C);
4453
4454 return (ima != nullptr && ima->source == IMA_SRC_TILED && !BLI_listbase_is_single(&ima->tiles));
4455}
4456
4458{
4459 Image *ima = CTX_data_edit_image(C);
4460
4461 ImageTile *tile = static_cast<ImageTile *>(BLI_findlink(&ima->tiles, ima->active_tile_index));
4462 if (!BKE_image_remove_tile(ima, tile)) {
4463 return OPERATOR_CANCELLED;
4464 }
4465
4466 /* Ensure that the active index is valid. */
4468
4470
4471 return OPERATOR_FINISHED;
4472}
4473
4475{
4476 /* identifiers */
4477 ot->name = "Remove Tile";
4478 ot->description = "Removes a tile from the image";
4479 ot->idname = "IMAGE_OT_tile_remove";
4480
4481 /* API callbacks. */
4482 ot->poll = tile_remove_poll;
4483 ot->exec = tile_remove_exec;
4484
4485 /* flags */
4486 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4487}
4488
4490
4491/* -------------------------------------------------------------------- */
4494
4496{
4497 Image *ima = CTX_data_edit_image(C);
4498
4499 if (ima != nullptr && ima->source == IMA_SRC_TILED) {
4500 /* Filling secondary tiles is only allowed if the primary tile exists. */
4501 return (ima->active_tile_index == 0) || BKE_image_has_ibuf(ima, nullptr);
4502 }
4503 return false;
4504}
4505
4507{
4508 Image *ima = CTX_data_edit_image(C);
4509
4510 ImageTile *tile = static_cast<ImageTile *>(BLI_findlink(&ima->tiles, ima->active_tile_index));
4511 if (!do_fill_tile(op->ptr, ima, tile)) {
4512 return OPERATOR_CANCELLED;
4513 }
4514
4516
4517 return OPERATOR_FINISHED;
4518}
4519
4521{
4522 tile_fill_init(op->ptr, CTX_data_edit_image(C), nullptr);
4523
4525 op,
4526 300,
4527 IFACE_("Fill Tile With Generated Image"),
4529}
4530
4531static void tile_fill_draw(bContext * /*C*/, wmOperator *op)
4532{
4533 draw_fill_tile(op->ptr, op->layout);
4534}
4535
4537{
4538 /* identifiers */
4539 ot->name = "Fill Tile";
4540 ot->description = "Fill the current tile with a generated image";
4541 ot->idname = "IMAGE_OT_tile_fill";
4542
4543 /* API callbacks. */
4544 ot->poll = tile_fill_poll;
4545 ot->exec = tile_fill_exec;
4546 ot->invoke = tile_fill_invoke;
4547 ot->ui = tile_fill_draw;
4548
4549 /* flags */
4550 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4551
4552 def_fill_tile(ot->srna);
4553}
4554
void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
Image * CTX_data_edit_image(const bContext *C)
SpaceImage * CTX_wm_space_image(const bContext *C)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
@ G_FILE_AUTOPACK
void BKE_icon_changed(int icon_id)
Definition icons.cc:204
int BKE_icon_id_ensure(struct ID *id)
Definition icons.cc:267
int BKE_image_get_tile_from_pos(Image *ima, const float uv[2], float r_uv[2], float r_ofs[2])
RenderSlot * BKE_image_get_renderslot(Image *ima, int index)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_user_frame_calc(Image *ima, ImageUser *iuser, int cfra)
bool BKE_image_has_filepath(const Image *ima)
void BKE_image_mark_dirty(Image *image, ImBuf *ibuf)
Image * BKE_image_load_exists_in_lib(Main *bmain, std::optional< Library * > owner_library, const char *filepath, bool *r_exists=nullptr)
Image * BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
bool BKE_image_fill_tile(Image *ima, ImageTile *tile)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
RenderSlot * BKE_image_add_renderslot(Image *ima, const char *name)
void BKE_image_user_file_path(const ImageUser *iuser, const Image *ima, char *filepath)
bool BKE_image_memorypack(Image *ima)
void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
bool BKE_image_is_dirty(Image *image)
#define IMA_UDIM_MAX
Definition BKE_image.hh:40
Image * BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
void BKE_image_sort_tiles(Image *ima)
bool BKE_image_has_anim(Image *image)
void BKE_imageuser_default(ImageUser *iuser)
#define IMA_SIGNAL_SRC_CHANGE
Definition BKE_image.hh:164
bool BKE_image_is_multiview(const Image *ima)
#define IMA_SIGNAL_USER_NEW_IMAGE
Definition BKE_image.hh:166
void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy)
#define IMA_SIGNAL_RELOAD
Definition BKE_image.hh:161
void BKE_image_free_views(Image *image)
bool BKE_image_has_packedfile(const Image *image)
bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int slot)
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
bool BKE_image_clear_renderslot(Image *ima, ImageUser *iuser, int slot)
void BKE_image_init_imageuser(Image *ima, ImageUser *iuser)
ImageTile * BKE_image_add_tile(Image *ima, int tile_number, const char *label)
bool BKE_image_remove_tile(Image *ima, ImageTile *tile)
bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
void BKE_image_free_packedfiles(Image *image)
bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable)
Image * BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], bool stereo3d, bool is_data, bool tiled)
bool BKE_image_buffer_format_writable(ImBuf *ibuf)
void BKE_image_format_free(ImageFormatData *imf)
void BKE_image_format_init_for_write(ImageFormatData *imf, const Scene *scene_src, const ImageFormatData *imf_src)
void BKE_image_format_set(ImageFormatData *imf, ID *owner_id, const char imtype)
bool BKE_image_save(ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts)
bool BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene, Image *ima, ImageUser *iuser, const bool guess_path, const bool save_as_render)
Definition image_save.cc:45
void BKE_image_save_options_update(ImageSaveOptions *opts, const Image *image)
void BKE_image_save_options_free(ImageSaveOptions *opts)
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
void BKE_id_move_to_same_lib(Main &bmain, ID &id, const ID &owner_id)
Definition lib_id.cc:869
void id_us_min(ID *id)
Definition lib_id.cc:361
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
void BKE_mask_coord_to_image(struct Image *image, struct ImageUser *iuser, float r_co[2], const float co[2])
int BKE_packedfile_unpack_image(Main *bmain, ReportList *reports, Image *ima, enum ePF_FileStatus how)
ePF_FileStatus
@ PF_USE_LOCAL
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_reports_free(ReportList *reports)
Definition report.cc:70
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:55
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2927
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:373
bool BLI_file_is_writable(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition fileops_c.cc:291
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE float power_of_2(float f)
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool BLI_path_extension_check_array(const char *path, const char **ext_array) ATTR_NONNULL(1
#define FILE_MAX
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
const char * BLI_path_slash_rfind(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition BLI_rect.h:185
void BLI_rctf_scale(rctf *rect, float scale)
Definition rct.cc:677
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.cc:404
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
#define STR_ELEM(...)
Definition BLI_string.h:656
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
unsigned char uchar
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:65
#define CLAMP(a, b, c)
#define CLAMP_MAX(a, c)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define STREQ(a, b)
#define RPT_(msgid)
#define BLT_I18NCONTEXT_ID_IMAGE
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_FRAME_CHANGE
Definition DNA_ID.h:1033
@ ID_RECALC_SOURCE
Definition DNA_ID.h:1051
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_EDITORS
Definition DNA_ID.h:1019
@ ID_IM
@ HISTO_FLAG_SAMPLELINE
@ IMA_GEN_FLOAT
@ IMA_SRC_FILE
@ IMA_SRC_MOVIE
@ IMA_SRC_GENERATED
@ IMA_SRC_VIEWER
@ IMA_SRC_TILED
@ IMA_SRC_SEQUENCE
@ IMA_USE_VIEWS
@ IMA_VIEW_AS_RENDER
@ IMA_TYPE_MULTILAYER
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
@ IMA_GENTYPE_BLANK
Object is a sort of wrapper for general info.
#define MINAFRAME
@ R_IMF_IMTYPE_PNG
@ R_IMF_CHAN_DEPTH_8
@ R_CROP
@ R_BORDER
@ R_MULTIVIEW
#define MAXFRAME
@ RGN_TYPE_WINDOW
struct ARegion ARegion
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_MOVIE
@ FILE_TYPE_FOLDER
@ FILE_TYPE_IMAGE
@ SPACE_IMAGE
@ FILE_DEFAULTDISPLAY
@ SI_MODE_PAINT
struct SpaceImage SpaceImage
@ TEX_IMAGE
#define FRAMENUMBER_MIN_CLAMP(cfra)
@ USER_ZOOM_INVERT
@ USER_ZOOM_TO_MOUSEPOS
@ USER_ZOOM_HORIZ
#define NDOF_PIXELS_PER_SECOND
@ USER_ZOOM_SCALE
@ USER_ZOOM_CONTINUE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_space_image_release_buffer(SpaceImage *sima, ImBuf *ibuf, void *lock)
void ED_space_image_get_size(SpaceImage *sima, int *r_width, int *r_height)
ImBuf * ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile)
bool ED_space_image_check_show_maskedit(SpaceImage *sima, Object *obedit)
void ED_space_image_set(Main *bmain, SpaceImage *sima, Image *ima, bool automatic)
Definition image_edit.cc:46
ListBase ED_image_filesel_detect_sequences(blender::StringRefNull root_path, wmOperator *op, bool detect_udim)
bool ED_space_image_has_buffer(SpaceImage *sima)
bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
bool ED_image_slot_cycle(Image *image, int direction)
void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
bool ED_space_image_cursor_poll(bContext *C)
Image * ED_space_image(const SpaceImage *sima)
Definition image_edit.cc:40
void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
bool ED_space_image_show_cache_and_mval_over(const SpaceImage *sima, ARegion *region, const int mval[2])
bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2], bool handles_as_control_point)
bool ED_maskedit_poll(bContext *C)
Definition mask_edit.cc:28
void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf, ImageUser *iuser)
void ED_image_undo_push_begin_with_image_all_udims(const char *name, Image *image, ImageUser *iuser)
void ED_image_undo_push_end()
void ED_imapaint_clear_partial_redraw()
void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:714
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
bool ED_operator_uvedit(bContext *C)
void ED_undo_push_op(bContext *C, wmOperator *op)
Definition ed_undo.cc:358
void unpack_menu(bContext *C, const char *opname, const char *id_name, const char *abs_name, const char *folder, PackedFile *pf)
Definition ed_util.cc:356
void ED_imbuf_sample_cancel(bContext *C, wmOperator *op)
wmOperatorStatus ED_imbuf_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_imbuf_sample_poll(bContext *C)
wmOperatorStatus ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_uvedit_minmax_multi(const Scene *scene, blender::Span< Object * > objects_edit, float r_min[2], float r_max[2])
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], const ColorSpace *colorspace)
ImBuf * IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, const ImageFormatData *image_format)
void IMB_byte_from_float(ImBuf *ibuf)
void IMB_freeImBuf(ImBuf *ibuf)
bool IMB_rotate_orthogonal(ImBuf *ibuf, int degrees)
bool IMB_save_image(ImBuf *ibuf, const char *filepath, const int flags)
Definition writeimage.cc:20
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:777
const char * imb_ext_movie[]
@ IB_BITMAPDIRTY
@ IB_MIPMAP_INVALID
@ IB_DISPLAY_BUFFER_INVALID
@ IB_byte_data
@ IMB_COLORMANAGE_IS_DATA
MovieCacheIter * IMB_moviecacheIter_new(MovieCache *cache)
void IMB_moviecacheIter_free(MovieCacheIter *iter)
bool IMB_moviecacheIter_done(MovieCacheIter *iter)
void IMB_moviecacheIter_step(MovieCacheIter *iter)
ImBuf * IMB_moviecacheIter_getImBuf(MovieCacheIter *iter)
Read Guarded memory(de)allocation.
@ IMB_TC_RECORD_RUN
Definition MOV_enums.hh:54
void StructOrFunctionRNA
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
@ PROP_PIXEL
Definition RNA_types.hh:236
@ PROP_COLOR_GAMMA
Definition RNA_types.hh:260
#define C
Definition RandGen.cpp:29
void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_management)
@ UI_BUT_LABEL_ALIGN_NONE
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr, bool(*check_prop)(PointerRNA *ptr, PropertyRNA *prop, void *user_data), void *user_data, PropertyRNA *prop_activate_init, eButLabelAlign label_align, bool compact)
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1667
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1674
@ WM_FILESEL_FILES
Definition WM_api.hh:1076
@ WM_FILESEL_DIRECTORY
Definition WM_api.hh:1073
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1072
@ WM_FILESEL_SHOW_PROPS
Definition WM_api.hh:1078
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1075
@ FILE_OPENFILE
Definition WM_api.hh:1084
@ FILE_SAVE
Definition WM_api.hh:1085
@ KM_ALT
Definition WM_types.hh:277
@ KM_SHIFT
Definition WM_types.hh:275
#define ND_DRAW
Definition WM_types.hh:458
#define ND_RENDER_OPTIONS
Definition WM_types.hh:432
@ KM_RELEASE
Definition WM_types.hh:309
#define NC_SCENE
Definition WM_types.hh:375
#define NA_ADDED
Definition WM_types.hh:583
#define ND_SPACE_IMAGE
Definition WM_types.hh:519
#define NA_EDITED
Definition WM_types.hh:581
ReportList * reports
Definition WM_types.hh:1025
#define NC_IMAGE
Definition WM_types.hh:381
#define ND_FRAME
Definition WM_types.hh:431
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:245
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_LOCK_BYPASS
Definition WM_types.hh:205
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_GRAB_CURSOR_XY
Definition WM_types.hh:188
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_SPACE
Definition WM_types.hh:389
static wmOperatorStatus change_frame_exec(bContext *C, wmOperator *op)
Definition anim_ops.cc:580
static wmOperatorStatus change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition anim_ops.cc:742
static wmOperatorStatus change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition anim_ops.cc:669
static float frame_from_event(bContext *C, const wmEvent *event)
Definition anim_ops.cc:590
static bool change_frame_poll(bContext *C)
Definition anim_ops.cc:97
volatile int lock
#define U
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
bool contains_as(const ForwardKey &key) const
Definition BLI_set.hh:314
bool add(const Key &key)
Definition BLI_set.hh:248
static wmOperatorStatus view_center_cursor_exec(bContext *C, wmOperator *)
Definition clip_ops.cc:1000
#define powf(x, y)
#define ceilf(x)
#define floorf(x)
#define offsetof(t, d)
uint col
#define active
constexpr T degrees(T) RET
#define ID_IS_LINKED(_id)
#define MAX_ID_NAME
#define ID_BLEND_PATH(_bmain, _id)
#define ID_IS_EDITABLE(_id)
#define GS(a)
bool space_image_main_region_poll(bContext *C)
Definition image_ops.cc:331
@ GEN_CONTEXT_NONE
@ GEN_CONTEXT_PAINT_CANVAS
@ GEN_CONTEXT_PAINT_STENCIL
static wmOperatorStatus image_match_len_exec(bContext *C, wmOperator *)
void IMAGE_OT_view_cursor_center(wmOperatorType *ot)
Definition image_ops.cc:899
static wmOperatorStatus image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:443
static bool tile_remove_poll(bContext *C)
void IMAGE_OT_change_frame(wmOperatorType *ot)
int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports)
static bool image_pack_poll(bContext *C)
static void image_filesel(bContext *C, wmOperator *op, const char *path)
void IMAGE_OT_save_sequence(wmOperatorType *ot)
static bool save_image_op(Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, const ImageSaveOptions *opts)
static bool image_has_valid_path(Image *ima)
static wmOperatorStatus image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *)
static bool image_should_be_saved(Image *ima, bool *r_is_format_writable)
static wmOperatorStatus image_sample_line_exec(bContext *C, wmOperator *op)
void IMAGE_OT_view_zoom(wmOperatorType *ot)
Definition image_ops.cc:735
static wmOperatorStatus image_save_exec(bContext *C, wmOperator *op)
void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
void IMAGE_OT_match_movie_length(wmOperatorType *ot)
static void tile_add_draw(bContext *, wmOperator *op)
static wmOperatorStatus image_reload_exec(bContext *C, wmOperator *)
void IMAGE_OT_save_all_modified(wmOperatorType *ot)
void IMAGE_OT_save_as(wmOperatorType *ot)
static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOperator *op)
static bool image_view_selected_poll(bContext *C)
static wmOperatorStatus image_pack_exec(bContext *C, wmOperator *op)
void IMAGE_OT_sample(wmOperatorType *ot)
static wmOperatorStatus image_file_browse_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *)
static bool image_pack_test(Image *ima, const char **r_error_message)
static wmOperatorStatus image_open_invoke(bContext *C, wmOperator *op, const wmEvent *)
static bool image_open_draw_check_prop(PointerRNA *, PropertyRNA *prop, void *)
static wmOperatorStatus tile_add_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void sima_zoom_set_factor(SpaceImage *sima, ARegion *region, float zoomfac, const float location[2], const bool zoom_to_pos)
Definition image_ops.cc:138
static void image_new_cancel(bContext *, wmOperator *op)
static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
Definition image_ops.cc:394
bool ED_image_should_save_modified(const Main *bmain)
static wmOperatorStatus image_remove_render_slot_exec(bContext *C, wmOperator *)
static void image_save_as_draw(bContext *, wmOperator *op)
static void image_view_zoom_cancel(bContext *C, wmOperator *op)
Definition image_ops.cc:730
static void def_fill_tile(StructOrFunctionRNA *srna)
static Image * image_from_context(const bContext *C)
Definition image_ops.cc:175
void IMAGE_OT_tile_fill(wmOperatorType *ot)
static bool tile_add_poll(bContext *C)
void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
static bool image_clipboard_paste_poll(bContext *C)
static wmOperatorStatus image_scale_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_save_as_exec(bContext *C, wmOperator *op)
static bool image_save_as_check(bContext *C, wmOperator *op)
static wmOperatorStatus image_new_exec(bContext *C, wmOperator *op)
static bool do_fill_tile(PointerRNA *ptr, Image *ima, ImageTile *tile)
static wmOperatorStatus image_view_zoom_in_exec(bContext *C, wmOperator *op)
void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
static bool image_from_context_has_data_poll(bContext *C)
Definition image_ops.cc:227
static bool tile_fill_poll(bContext *C)
static wmOperatorStatus image_save_sequence_exec(bContext *C, wmOperator *op)
static wmOperatorStatus tile_remove_exec(bContext *C, wmOperator *)
static wmOperatorStatus image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:425
void IMAGE_OT_reload(wmOperatorType *ot)
void IMAGE_OT_unpack(wmOperatorType *ot)
void IMAGE_OT_view_selected(wmOperatorType *ot)
void IMAGE_OT_tile_add(wmOperatorType *ot)
void IMAGE_OT_pack(wmOperatorType *ot)
void IMAGE_OT_open(wmOperatorType *ot)
void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
static void image_view_all(SpaceImage *sima, ARegion *region, wmOperator *op)
Definition image_ops.cc:267
static void image_operator_prop_allow_tokens(wmOperatorType *ot)
static bool image_save_as_poll(bContext *C)
static bool image_clipboard_copy_poll(bContext *C)
static wmOperatorStatus change_frame_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_add_render_slot_exec(bContext *C, wmOperator *)
static wmOperatorStatus image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *)
void IMAGE_OT_invert(wmOperatorType *ot)
static void image_open_cancel(bContext *, wmOperator *op)
void IMAGE_OT_resize(wmOperatorType *ot)
void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
static wmOperatorStatus tile_fill_exec(bContext *C, wmOperator *op)
void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
void IMAGE_OT_rotate_orthogonal(wmOperatorType *ot)
static void tile_fill_draw(bContext *, wmOperator *op)
void IMAGE_OT_view_all(wmOperatorType *ot)
Definition image_ops.cc:853
static wmOperatorStatus image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:683
void IMAGE_OT_render_border(wmOperatorType *ot)
static wmOperatorStatus image_read_viewlayers_exec(bContext *C, wmOperator *)
static wmOperatorStatus image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
void IMAGE_OT_view_pan(wmOperatorType *ot)
Definition image_ops.cc:474
static int frame_from_event(bContext *C, const wmEvent *event)
static void draw_fill_tile(PointerRNA *ptr, uiLayout *layout)
static wmOperatorStatus image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus image_clipboard_copy_exec(bContext *C, wmOperator *op)
void IMAGE_OT_clipboard_copy(wmOperatorType *ot)
static wmOperatorStatus image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus image_cycle_render_slot_exec(bContext *C, wmOperator *op)
static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:530
static bool image_not_packed_poll(bContext *C)
Definition image_ops.cc:260
static wmOperatorStatus image_new_invoke(bContext *C, wmOperator *op, const wmEvent *)
static void image_save_as_free(wmOperator *op)
static wmOperatorStatus change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bool image_file_format_writable(Image *ima, ImageUser *iuser)
static bool image_should_be_saved_when_modified(Image *ima)
void IMAGE_OT_save(wmOperatorType *ot)
static wmOperatorStatus image_rotate_orthogonal_exec(bContext *C, wmOperator *op)
static wmOperatorStatus tile_add_exec(bContext *C, wmOperator *op)
static void image_save_as_cancel(bContext *, wmOperator *op)
static void image_open_draw(bContext *, wmOperator *op)
void IMAGE_OT_file_browse(wmOperatorType *ot)
static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:371
static wmOperatorStatus image_view_all_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:837
static wmOperatorStatus change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus image_save_all_modified_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_flip_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_save_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
Definition image_ops.cc:565
@ VIEW_CONFIRM
Definition image_ops.cc:600
@ VIEW_PASS
Definition image_ops.cc:598
@ VIEW_APPLY
Definition image_ops.cc:599
static ImageSaveData * image_save_as_init(bContext *C, wmOperator *op)
void IMAGE_OT_clipboard_paste(wmOperatorType *ot)
static bool image_cycle_render_slot_poll(bContext *C)
static wmOperatorStatus image_view_zoom_out_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus render_border_exec(bContext *C, wmOperator *op)
static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *user_data)
static wmOperatorStatus view_cursor_center_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:880
void IMAGE_OT_add_render_slot(wmOperatorType *ot)
void IMAGE_OT_tile_remove(wmOperatorType *ot)
static wmOperatorStatus tile_fill_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:603
static void image_open_init(bContext *C, wmOperator *op)
static void tile_fill_init(PointerRNA *ptr, Image *ima, ImageTile *tile)
static wmOperatorStatus image_invert_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_unpack_exec(bContext *C, wmOperator *op)
bool space_image_main_region_poll(bContext *C)
Definition image_ops.cc:331
bool ED_space_image_get_position(SpaceImage *sima, ARegion *region, const int mval[2], float r_fpos[2])
static Image * image_open_single(Main *bmain, Library *owner_library, wmOperator *op, const ImageFrameRange *range, const bool use_multiview)
void IMAGE_OT_flip(wmOperatorType *ot)
static bool image_save_all_modified_poll(bContext *C)
static wmOperatorStatus image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *)
static bool image_should_pack_during_save_all(const Image *ima)
void IMAGE_OT_sample_line(wmOperatorType *ot)
static wmOperatorStatus image_view_zoom_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:585
void IMAGE_OT_replace(wmOperatorType *ot)
static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *region, const rctf *bounds)
Definition image_ops.cc:150
static bool change_frame_poll(bContext *C)
static ImageNewData * image_new_init(bContext *C, wmOperator *op)
static bool image_save_poll(bContext *C)
static void image_view_pan_cancel(bContext *C, wmOperator *op)
Definition image_ops.cc:469
static wmOperatorStatus image_replace_exec(bContext *C, wmOperator *op)
static void sima_zoom_set(SpaceImage *sima, ARegion *region, float zoom, const float location[2], const bool zoom_to_pos)
Definition image_ops.cc:98
static wmOperatorStatus image_file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus view_center_cursor_exec(bContext *C, wmOperator *)
Definition image_ops.cc:923
static wmOperatorStatus image_view_pan_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:411
void IMAGE_OT_view_center_cursor(wmOperatorType *ot)
Definition image_ops.cc:935
bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
static wmOperatorStatus image_view_zoom_border_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_open_exec(bContext *C, wmOperator *op)
static void image_new_draw(bContext *, wmOperator *op)
static wmOperatorStatus clear_render_border_exec(bContext *C, wmOperator *)
static ImageUser image_user_from_context_and_active_tile(const bContext *C, Image *ima)
Definition image_ops.cc:206
void IMAGE_OT_new(wmOperatorType *ot)
static void change_frame_apply(bContext *C, wmOperator *op)
bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, const int mval[2], float r_col[3], bool *r_is_data)
static bool image_file_browse_poll(bContext *C)
static ImageUser * image_user_from_context(const bContext *C)
Definition image_ops.cc:190
static void image_new_free(wmOperator *op)
void IMAGE_OT_clear_render_border(wmOperatorType *ot)
static bool space_image_main_area_not_uv_brush_poll(bContext *C)
Definition image_ops.cc:343
static wmOperatorStatus image_clipboard_paste_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_view_selected_exec(bContext *C, wmOperator *)
Definition image_ops.cc:953
void IMAGE_OT_curves_point_set(wmOperatorType *ot)
static bool image_from_context_editable_has_data_poll_active_tile(bContext *C)
Definition image_ops.cc:246
static wmOperatorStatus image_clear_render_slot_exec(bContext *C, wmOperator *)
static void image_zoom_apply(ViewZoomData *vpd, wmOperator *op, const int x, const int y, const short viewzoom, const short zoom_invert, const bool zoom_to_pos)
Definition image_ops.cc:636
RenderData * RE_engine_get_render_data(Render *re)
const ccl_global KernelWorkTile * tile
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
int MOV_get_duration_frames(MovieReader *anim, IMB_Timecode_Type tc)
VecBase< float, 3 > float3
#define IMA_DEF_NAME
return ret
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
void RNA_property_int_set_array(PointerRNA *ptr, PropertyRNA *prop, const int *values)
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
const char * RNA_property_identifier(const PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_float_color(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_int_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const int *default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_image_generated_type_items[]
Definition rna_image.cc:24
const EnumPropertyItem rna_enum_unpack_method_items[]
#define min(a, b)
Definition sort.cc:36
Render * RE_GetSceneRender(const Scene *scene)
bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
#define FLT_MAX
Definition stdcycles.h:14
struct ListBase bg_images
float co[2][2]
Definition DNA_ID.h:404
struct Library * lib
Definition DNA_ID.h:410
char name[66]
Definition DNA_ID.h:415
const ColorSpace * colorspace
char filepath[IMB_FILEPATH_SIZE]
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
int colormanage_flag
unsigned char planes
ImBuf * mipmap[IMB_MIPMAP_LEVELS]
Stereo3dFormat stereo3d_format
char filepath[FILE_MAX]
Definition ED_image.hh:195
ListBase udim_tiles
Definition ED_image.hh:201
PropertyPointerRNA pprop
ImageUser * iuser
ImageFormatData im_format
PropertyPointerRNA pprop
ImageSaveOptions opts
ImageUser * iuser
ImageFormatData im_format
struct Scene * scene
struct MovieCache * cache
struct ListBase packedfiles
short last_render_slot
ListBase anims
ListBase renderslots
char views_format
char filepath[1024]
ListBase tiles
short source
short render_slot
struct Stereo3dFormat * stereo3d_format
int active_tile_index
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:516
void * first
ListBase images
Definition BKE_main.hh:253
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
PropertyRNA * prop
Definition RNA_types.hh:134
struct RenderResult * render
ColorManagedViewSettings view_settings
struct RenderData r
ColorManagedDisplaySettings display_settings
ListBase spacedata
float cursor[2]
int tile_grid_shape[2]
struct Histogram sample_line_hist
struct ImageUser iuser
struct Image * image
struct ImageUser iuser
struct Image * ima
float xmax
float xmin
float ymax
float ymin
uiLayout & column(bool align)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
wmEventModifierFlag modifier
Definition WM_types.hh:771
wmEventType type
Definition WM_types.hh:754
short val
Definition WM_types.hh:756
int xy[2]
Definition WM_types.hh:758
int mval[2]
Definition WM_types.hh:760
void * customdata
Definition WM_types.hh:804
const char * name
Definition WM_types.hh:1030
struct ReportList * reports
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
wmWindow * win
Definition WM_types.hh:953
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
void WM_cursor_wait(bool val)
@ WM_CURSOR_NSEW_SCROLL
Definition wm_cursors.hh:52
@ WM_CURSOR_EDIT
Definition wm_cursors.hh:19
int WM_userdef_event_type_from_keymap_type(int kmitype)
void WM_event_add_fileselect(bContext *C, wmOperator *op)
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
wmOperatorStatus WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ MOUSEPAN
@ RIGHTMOUSE
@ TIMER
@ MOUSEZOOM
@ MOUSEMOVE
@ LEFTMOUSE
@ NDOF_MOTION
@ EVT_ESCKEY
PointerRNA * ptr
Definition wm_files.cc:4227
wmOperatorType * ot
Definition wm_files.cc:4226
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
void WM_gesture_straightline_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_border_to_rctf(wmOperator *op, rctf *r_rect)
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
void WM_operator_properties_border(wmOperatorType *ot)
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
void WM_operator_properties_use_cursor_init(wmOperatorType *ot)
void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
wmOperatorStatus WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default)
bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const ImageFormatData *im_format)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
ImBuf * WM_clipboard_image_get()
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
bool WM_clipboard_image_available()
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
bool WM_clipboard_image_set_byte_buffer(ImBuf *ibuf)