Blender V5.0
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"
83#include "UI_resources.hh"
84#include "UI_view2d.hh"
85
86#include "WM_api.hh"
87#include "WM_types.hh"
88
89#include "RE_engine.h"
90
91#include "image_intern.hh"
92
93using blender::Vector;
94
95/* -------------------------------------------------------------------- */
98
99static void sima_zoom_set(
100 SpaceImage *sima, ARegion *region, float zoom, const float location[2], const bool zoom_to_pos)
101{
102 float oldzoom = sima->zoom;
103 int width, height;
104
105 sima->zoom = zoom;
106
107 if (sima->zoom < 0.1f || sima->zoom > 4.0f) {
108 /* check zoom limits */
109 ED_space_image_get_size(sima, &width, &height);
110
111 width *= sima->zoom;
112 height *= sima->zoom;
113
114 if ((width < 4) && (height < 4) && sima->zoom < oldzoom) {
115 sima->zoom = oldzoom;
116 }
117 else if (BLI_rcti_size_x(&region->winrct) <= sima->zoom) {
118 sima->zoom = oldzoom;
119 }
120 else if (BLI_rcti_size_y(&region->winrct) <= sima->zoom) {
121 sima->zoom = oldzoom;
122 }
123 }
124
125 if (zoom_to_pos && location) {
126 float aspx, aspy, w, h;
127
128 ED_space_image_get_size(sima, &width, &height);
129 ED_space_image_get_aspect(sima, &aspx, &aspy);
130
131 w = width * aspx;
132 h = height * aspy;
133
134 sima->xof += ((location[0] - 0.5f) * w - sima->xof) * (sima->zoom - oldzoom) / sima->zoom;
135 sima->yof += ((location[1] - 0.5f) * h - sima->yof) * (sima->zoom - oldzoom) / sima->zoom;
136 }
137}
138
140 ARegion *region,
141 float zoomfac,
142 const float location[2],
143 const bool zoom_to_pos)
144{
145 sima_zoom_set(sima, region, sima->zoom * zoomfac, location, zoom_to_pos);
146}
147
151static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *region, const rctf *bounds)
152{
153 int image_size[2];
154 float aspx, aspy;
155
156 ED_space_image_get_size(sima, &image_size[0], &image_size[1]);
157 ED_space_image_get_aspect(sima, &aspx, &aspy);
158
159 image_size[0] = image_size[0] * aspx;
160 image_size[1] = image_size[1] * aspy;
161
162 /* adjust offset and zoom */
163 sima->xof = roundf((BLI_rctf_cent_x(bounds) - 0.5f) * image_size[0]);
164 sima->yof = roundf((BLI_rctf_cent_y(bounds) - 0.5f) * image_size[1]);
165
166 float size_xy[2], size;
167 size_xy[0] = BLI_rcti_size_x(&region->winrct) / (BLI_rctf_size_x(bounds) * image_size[0]);
168 size_xy[1] = BLI_rcti_size_y(&region->winrct) / (BLI_rctf_size_y(bounds) * image_size[1]);
169
170 size = min_ff(size_xy[0], size_xy[1]);
171 CLAMP_MAX(size, 100.0f);
172
173 sima_zoom_set(sima, region, size, nullptr, false);
174}
175
177{
178 /* Edit image is set by templates used throughout the interface, so image
179 * operations work outside the image editor. */
180 Image *ima = static_cast<Image *>(CTX_data_pointer_get_type(C, "edit_image", &RNA_Image).data);
181
182 if (ima) {
183 return ima;
184 }
185
186 /* Image editor. */
188 return (sima) ? sima->image : nullptr;
189}
190
192{
193 /* Edit image user is set by templates used throughout the interface, so
194 * image operations work outside the image editor. */
195 ImageUser *iuser = static_cast<ImageUser *>(
196 CTX_data_pointer_get_type(C, "edit_image_user", &RNA_ImageUser).data);
197
198 if (iuser) {
199 return iuser;
200 }
201
202 /* Image editor. */
204 return (sima) ? &sima->iuser : nullptr;
205}
206
208{
209 /* Try to get image user from context if available, otherwise use default. */
210 ImageUser *iuser_context = image_user_from_context(C);
211 ImageUser iuser;
212 if (iuser_context) {
213 iuser = *iuser_context;
214 }
215 else {
216 BKE_imageuser_default(&iuser);
217 }
218
219 /* Use the file associated with the active tile. Otherwise use the first tile. */
220 if (ima && ima->source == IMA_SRC_TILED) {
222 iuser.tile = active ? active->tile_number : ((ImageTile *)ima->tiles.first)->tile_number;
223 }
224
225 return iuser;
226}
227
229{
230 Image *ima = image_from_context(C);
232
233 if (ima == nullptr) {
234 return false;
235 }
236
237 void *lock;
238 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
239 const bool has_buffer = (ibuf && (ibuf->byte_buffer.data || ibuf->float_buffer.data));
240 BKE_image_release_ibuf(ima, ibuf, lock);
241 return has_buffer;
242}
243
248{
249 Image *ima = image_from_context(C);
250
251 if (ima && !ID_IS_EDITABLE(&ima->id)) {
252 CTX_wm_operator_poll_msg_set(C, "Image is not editable");
253 return false;
254 }
255
257
258 return BKE_image_has_ibuf(ima, &iuser);
259}
260
262{
263 /* Do not run 'replace' on packed images, it does not give user expected results at all. */
264 Image *ima = image_from_context(C);
265 return (ima && BLI_listbase_is_empty(&ima->packedfiles));
266}
267
268static void image_view_all(SpaceImage *sima, ARegion *region, wmOperator *op)
269{
270 float aspx, aspy, zoomx, zoomy, w, h;
271 int width, height;
272 const bool fit_view = RNA_boolean_get(op->ptr, "fit_view");
273
274 ED_space_image_get_size(sima, &width, &height);
275 ED_space_image_get_aspect(sima, &aspx, &aspy);
276
277 w = width * aspx;
278 h = height * aspy;
279
280 float xof = 0.0f, yof = 0.0f;
281 if ((sima->image == nullptr) || (sima->image->source == IMA_SRC_TILED)) {
282 /* Extend the shown area to cover all UDIM tiles. */
283 int x_tiles, y_tiles;
284 if (sima->image == nullptr) {
285 x_tiles = sima->tile_grid_shape[0];
286 y_tiles = sima->tile_grid_shape[1];
287 }
288 else {
289 x_tiles = y_tiles = 1;
291 int tile_x = (tile->tile_number - 1001) % 10;
292 int tile_y = (tile->tile_number - 1001) / 10;
293 x_tiles = max_ii(x_tiles, tile_x + 1);
294 y_tiles = max_ii(y_tiles, tile_y + 1);
295 }
296 }
297 xof = 0.5f * (x_tiles - 1.0f) * w;
298 yof = 0.5f * (y_tiles - 1.0f) * h;
299 w *= x_tiles;
300 h *= y_tiles;
301 }
302
303 /* check if the image will fit in the image with (zoom == 1) */
304 width = BLI_rcti_size_x(&region->winrct) + 1;
305 height = BLI_rcti_size_y(&region->winrct) + 1;
306
307 if (fit_view) {
308 const int margin = 5; /* margin from border */
309
310 zoomx = float(width) / (w + 2 * margin);
311 zoomy = float(height) / (h + 2 * margin);
312
313 sima_zoom_set(sima, region, min_ff(zoomx, zoomy), nullptr, false);
314 }
315 else {
316 if ((w >= width || h >= height) && (width > 0 && height > 0)) {
317 zoomx = float(width) / w;
318 zoomy = float(height) / h;
319
320 /* find the zoom value that will fit the image in the image space */
321 sima_zoom_set(sima, region, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), nullptr, false);
322 }
323 else {
324 sima_zoom_set(sima, region, 1.0f, nullptr, false);
325 }
326 }
327
328 sima->xof = xof;
329 sima->yof = yof;
330}
331
333{
335 // ARegion *region = CTX_wm_region(C); /* XXX. */
336
337 if (sima) {
338 return true; /* XXX (region && region->runtime->type->regionid == RGN_TYPE_WINDOW); */
339 }
340 return false;
341}
342
345{
347
348 if (sima && (CTX_data_edit_object(C) == nullptr)) {
349 return true;
350 }
351
352 return false;
353}
354
356
357/* -------------------------------------------------------------------- */
360
361namespace {
362
363struct ViewPanData {
364 float x, y;
365 float xof, yof;
366 int launch_event;
367 bool own_cursor;
368};
369
370} // namespace
371
372static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
373{
374 wmWindow *win = CTX_wm_window(C);
376 ViewPanData *vpd;
377
378 op->customdata = vpd = MEM_callocN<ViewPanData>("ImageViewPanData");
379
380 /* Grab will be set when running from gizmo. */
381 vpd->own_cursor = WM_cursor_modal_is_set_ok(win);
382 if (vpd->own_cursor) {
384 }
385
386 vpd->x = event->xy[0];
387 vpd->y = event->xy[1];
388 vpd->xof = sima->xof;
389 vpd->yof = sima->yof;
390 vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
391
393}
394
395static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
396{
398 ViewPanData *vpd = static_cast<ViewPanData *>(op->customdata);
399
400 if (cancel) {
401 sima->xof = vpd->xof;
402 sima->yof = vpd->yof;
404 }
405
406 if (vpd->own_cursor) {
408 }
409 MEM_freeN(vpd);
410}
411
413{
415 float offset[2];
416
417 RNA_float_get_array(op->ptr, "offset", offset);
418 sima->xof += offset[0];
419 sima->yof += offset[1];
420
422
423 return OPERATOR_FINISHED;
424}
425
427{
428 if (event->type == MOUSEPAN) {
430 float offset[2];
431
432 offset[0] = (event->prev_xy[0] - event->xy[0]) / sima->zoom;
433 offset[1] = (event->prev_xy[1] - event->xy[1]) / sima->zoom;
434 RNA_float_set_array(op->ptr, "offset", offset);
435
437 return OPERATOR_FINISHED;
438 }
439
440 image_view_pan_init(C, op, event);
442}
443
445{
447 ViewPanData *vpd = static_cast<ViewPanData *>(op->customdata);
448 float offset[2];
449
450 switch (event->type) {
451 case MOUSEMOVE:
452 sima->xof = vpd->xof;
453 sima->yof = vpd->yof;
454 offset[0] = (vpd->x - event->xy[0]) / sima->zoom;
455 offset[1] = (vpd->y - event->xy[1]) / sima->zoom;
456 RNA_float_set_array(op->ptr, "offset", offset);
458 break;
459 default:
460 if (event->type == vpd->launch_event && event->val == KM_RELEASE) {
461 image_view_pan_exit(C, op, false);
462 return OPERATOR_FINISHED;
463 }
464 break;
465 }
466
468}
469
471{
472 image_view_pan_exit(C, op, true);
473}
474
476{
477 /* identifiers */
478 ot->name = "Pan View";
479 ot->idname = "IMAGE_OT_view_pan";
480 ot->description = "Pan the view";
481
482 /* API callbacks. */
483 ot->exec = image_view_pan_exec;
484 ot->invoke = image_view_pan_invoke;
485 ot->modal = image_view_pan_modal;
486 ot->cancel = image_view_pan_cancel;
488
489 /* flags */
491
492 /* properties */
494 "offset",
495 2,
496 nullptr,
497 -FLT_MAX,
498 FLT_MAX,
499 "Offset",
500 "Offset in floating-point units, 1.0 is the width and height of the image",
501 -FLT_MAX,
502 FLT_MAX);
503}
504
506
507/* -------------------------------------------------------------------- */
510
511namespace {
512
513struct ViewZoomData {
514 float origx, origy;
515 float zoom;
516 int launch_event;
517 float location[2];
518
519 /* needed for continuous zoom */
520 wmTimer *timer;
521 double timer_lastdraw;
522 bool own_cursor;
523
524 /* */
525 SpaceImage *sima;
526 ARegion *region;
527};
528
529} // namespace
530
531static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
532{
533 wmWindow *win = CTX_wm_window(C);
535 ARegion *region = CTX_wm_region(C);
536 ViewZoomData *vpd;
537
538 op->customdata = vpd = MEM_callocN<ViewZoomData>("ImageViewZoomData");
539
540 /* Grab will be set when running from gizmo. */
541 vpd->own_cursor = WM_cursor_modal_is_set_ok(win);
542 if (vpd->own_cursor) {
544 }
545
546 vpd->origx = event->xy[0];
547 vpd->origy = event->xy[1];
548 vpd->zoom = sima->zoom;
549 vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
550
552 &region->v2d, event->mval[0], event->mval[1], &vpd->location[0], &vpd->location[1]);
553
554 if (U.viewzoom == USER_ZOOM_CONTINUE) {
555 /* needs a timer to continue redrawing */
556 vpd->timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
557 vpd->timer_lastdraw = BLI_time_now_seconds();
558 }
559
560 vpd->sima = sima;
561 vpd->region = region;
562
564}
565
566static void image_view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
567{
569 ViewZoomData *vpd = static_cast<ViewZoomData *>(op->customdata);
570
571 if (cancel) {
572 sima->zoom = vpd->zoom;
574 }
575
576 if (vpd->timer) {
577 WM_event_timer_remove(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
578 }
579
580 if (vpd->own_cursor) {
582 }
583 MEM_freeN(vpd);
584}
585
587{
589 ARegion *region = CTX_wm_region(C);
590
591 sima_zoom_set_factor(sima, region, RNA_float_get(op->ptr, "factor"), nullptr, false);
592
593 ED_region_tag_redraw(region);
594
595 return OPERATOR_FINISHED;
596}
597
598enum {
602};
603
605{
606 if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
608 ARegion *region = CTX_wm_region(C);
609 float delta, factor, location[2];
610
612 &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
613
614 delta = event->prev_xy[0] - event->xy[0] + event->prev_xy[1] - event->xy[1];
615
616 if (U.uiflag & USER_ZOOM_INVERT) {
617 delta *= -1;
618 }
619
620 factor = 1.0f + delta / 300.0f;
621 RNA_float_set(op->ptr, "factor", factor);
622 const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
623 sima_zoom_set(sima,
624 region,
625 sima->zoom * factor,
626 location,
627 (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
628 ED_region_tag_redraw(region);
629
630 return OPERATOR_FINISHED;
631 }
632
633 image_view_zoom_init(C, op, event);
635}
636
637static void image_zoom_apply(ViewZoomData *vpd,
638 wmOperator *op,
639 const int x,
640 const int y,
641 const short viewzoom,
642 const short zoom_invert,
643 const bool zoom_to_pos)
644{
645 float factor;
646 float delta;
647
648 if (viewzoom != USER_ZOOM_SCALE) {
649 if (U.uiflag & USER_ZOOM_HORIZ) {
650 delta = float(x - vpd->origx);
651 }
652 else {
653 delta = float(y - vpd->origy);
654 }
655 }
656 else {
657 delta = x - vpd->origx + y - vpd->origy;
658 }
659
660 delta /= U.pixelsize;
661
662 if (zoom_invert) {
663 delta = -delta;
664 }
665
666 if (viewzoom == USER_ZOOM_CONTINUE) {
667 double time = BLI_time_now_seconds();
668 float time_step = float(time - vpd->timer_lastdraw);
669 float zfac;
670 zfac = 1.0f + ((delta / 20.0f) * time_step);
671 vpd->timer_lastdraw = time;
672 /* this is the final zoom, but instead make it into a factor */
673 factor = (vpd->sima->zoom * zfac) / vpd->zoom;
674 }
675 else {
676 factor = 1.0f + delta / 300.0f;
677 }
678
679 RNA_float_set(op->ptr, "factor", factor);
680 sima_zoom_set(vpd->sima, vpd->region, vpd->zoom * factor, vpd->location, zoom_to_pos);
681 ED_region_tag_redraw(vpd->region);
682}
683
685{
686 ViewZoomData *vpd = static_cast<ViewZoomData *>(op->customdata);
687 short event_code = VIEW_PASS;
689
690 /* Execute the events. */
691 if (event->type == MOUSEMOVE) {
692 event_code = VIEW_APPLY;
693 }
694 else if (event->type == TIMER) {
695 /* Continuous zoom. */
696 if (event->customdata == vpd->timer) {
697 event_code = VIEW_APPLY;
698 }
699 }
700 else if (event->type == vpd->launch_event) {
701 if (event->val == KM_RELEASE) {
702 event_code = VIEW_CONFIRM;
703 }
704 }
705
706 switch (event_code) {
707 case VIEW_APPLY: {
708 const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
710 op,
711 event->xy[0],
712 event->xy[1],
713 U.viewzoom,
714 (U.uiflag & USER_ZOOM_INVERT) != 0,
715 (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
716 break;
717 }
718 case VIEW_CONFIRM: {
720 break;
721 }
722 }
723
724 if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
725 image_view_zoom_exit(C, op, false);
726 }
727
728 return ret;
729}
730
732{
733 image_view_zoom_exit(C, op, true);
734}
735
737{
738 PropertyRNA *prop;
739
740 /* identifiers */
741 ot->name = "Zoom View";
742 ot->idname = "IMAGE_OT_view_zoom";
743 ot->description = "Zoom in/out the image";
744
745 /* API callbacks. */
746 ot->exec = image_view_zoom_exec;
747 ot->invoke = image_view_zoom_invoke;
748 ot->modal = image_view_zoom_modal;
749 ot->cancel = image_view_zoom_cancel;
751
752 /* flags */
754
755 /* properties */
756 prop = RNA_def_float(ot->srna,
757 "factor",
758 0.0f,
759 -FLT_MAX,
760 FLT_MAX,
761 "Factor",
762 "Zoom factor, values higher than 1.0 zoom in, lower values zoom out",
763 -FLT_MAX,
764 FLT_MAX);
766
768}
769
771
772#ifdef WITH_INPUT_NDOF
773
774/* -------------------------------------------------------------------- */
777
778/* Combined pan/zoom from a 3D mouse device.
779 * Z zooms, XY pans
780 * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
781 * that explains the negative signs in the code below
782 */
783
784static wmOperatorStatus image_view_ndof_invoke(bContext *C,
785 wmOperator * /*op*/,
786 const wmEvent *event)
787{
788 if (event->type != NDOF_MOTION) {
789 return OPERATOR_CANCELLED;
790 }
791
793 ARegion *region = CTX_wm_region(C);
794
795 const wmNDOFMotionData &ndof = *static_cast<const wmNDOFMotionData *>(event->customdata);
796 const float pan_speed = NDOF_PIXELS_PER_SECOND;
797
798 blender::float3 pan_vec = ndof.time_delta * WM_event_ndof_translation_get_for_navigation(ndof);
799
800 mul_v2_fl(pan_vec, pan_speed / sima->zoom);
801
802 sima_zoom_set_factor(sima, region, max_ff(0.0f, 1.0f - pan_vec[2]), nullptr, false);
803 sima->xof += pan_vec[0];
804 sima->yof += pan_vec[1];
805
806 ED_region_tag_redraw(region);
807
808 return OPERATOR_FINISHED;
809}
810
811void IMAGE_OT_view_ndof(wmOperatorType *ot)
812{
813 /* identifiers */
814 ot->name = "NDOF Pan/Zoom";
815 ot->idname = "IMAGE_OT_view_ndof";
816 ot->description = "Use a 3D mouse device to pan/zoom the view";
817
818 /* API callbacks. */
819 ot->invoke = image_view_ndof_invoke;
821
822 /* flags */
823 ot->flag = OPTYPE_LOCK_BYPASS;
824}
825
827
828#endif /* WITH_INPUT_NDOF */
829
830/* -------------------------------------------------------------------- */
833
834/* Updates the fields of the View2D member of the SpaceImage struct.
835 * Default behavior is to reset the position of the image and set the zoom to 1
836 * If the image will not fit within the window rectangle, the zoom is adjusted */
837
839{
840 SpaceImage *sima;
841 ARegion *region;
842
843 /* retrieve state */
844 sima = CTX_wm_space_image(C);
845 region = CTX_wm_region(C);
846
847 image_view_all(sima, region, op);
848
849 ED_region_tag_redraw(region);
850
851 return OPERATOR_FINISHED;
852}
853
855{
856 PropertyRNA *prop;
857
858 /* identifiers */
859 ot->name = "Frame All";
860 ot->idname = "IMAGE_OT_view_all";
861 ot->description = "View the entire image";
862
863 /* API callbacks. */
864 ot->exec = image_view_all_exec;
866
867 /* flags */
868 ot->flag = OPTYPE_LOCK_BYPASS;
869
870 /* properties */
871 prop = RNA_def_boolean(ot->srna, "fit_view", false, "Fit View", "Fit frame to the viewport");
873}
874
876
877/* -------------------------------------------------------------------- */
880
882{
883 SpaceImage *sima;
884 ARegion *region;
885
886 sima = CTX_wm_space_image(C);
887 region = CTX_wm_region(C);
888
889 image_view_all(sima, region, op);
890
891 sima->cursor[0] = 0.5f;
892 sima->cursor[1] = 0.5f;
893
894 /* Needed for updating the cursor. */
896
897 return OPERATOR_FINISHED;
898}
899
901{
902 PropertyRNA *prop;
903
904 /* identifiers */
905 ot->name = "Cursor To Center View";
906 ot->description = "Set 2D Cursor To Center View location";
907 ot->idname = "IMAGE_OT_view_cursor_center";
908
909 /* API callbacks. */
912
913 /* properties */
914 prop = RNA_def_boolean(ot->srna, "fit_view", false, "Fit View", "Fit frame to the viewport");
916}
917
919
920/* -------------------------------------------------------------------- */
923
925{
927 ARegion *region = CTX_wm_region(C);
928
929 ED_image_view_center_to_point(sima, sima->cursor[0], sima->cursor[1]);
930
931 ED_region_tag_redraw(region);
932
933 return OPERATOR_FINISHED;
934}
935
937{
938 /* identifiers */
939 ot->name = "Center View to Cursor";
940 ot->description = "Center the view so that the cursor is in the middle of the view";
941 ot->idname = "IMAGE_OT_view_center_cursor";
942
943 /* API callbacks. */
946}
947
949
950/* -------------------------------------------------------------------- */
953
955{
956 SpaceImage *sima;
957 ARegion *region;
958 Scene *scene;
959 ViewLayer *view_layer;
960 Object *obedit;
961
962 /* retrieve state */
963 sima = CTX_wm_space_image(C);
964 region = CTX_wm_region(C);
965 scene = CTX_data_scene(C);
966 view_layer = CTX_data_view_layer(C);
967 obedit = CTX_data_edit_object(C);
968
969 /* get bounds */
970 float min[2], max[2];
971 if (ED_space_image_show_uvedit(sima, obedit)) {
973 scene, view_layer, nullptr);
974 bool success = ED_uvedit_minmax_multi(scene, objects, min, max);
975 if (!success) {
976 return OPERATOR_CANCELLED;
977 }
978 }
979 else if (ED_space_image_check_show_maskedit(sima, obedit)) {
980 if (!ED_mask_selected_minmax(C, min, max, false)) {
981 return OPERATOR_CANCELLED;
982 }
983 BKE_mask_coord_to_image(sima->image, &sima->iuser, min, min);
984 BKE_mask_coord_to_image(sima->image, &sima->iuser, max, max);
985 }
986 rctf bounds{};
987 bounds.xmin = min[0];
988 bounds.ymin = min[1];
989 bounds.xmax = max[0];
990 bounds.ymax = max[1];
991
992 /* add some margin */
993 BLI_rctf_scale(&bounds, 1.4f);
994
995 sima_zoom_set_from_bounds(sima, region, &bounds);
996
997 ED_region_tag_redraw(region);
998
999 return OPERATOR_FINISHED;
1000}
1001
1006
1008{
1009 /* identifiers */
1010 ot->name = "View Center";
1011 ot->idname = "IMAGE_OT_view_selected";
1012 ot->description = "View all selected UVs";
1013
1014 /* API callbacks. */
1017}
1018
1020
1021/* -------------------------------------------------------------------- */
1024
1026{
1028 ARegion *region = CTX_wm_region(C);
1029 float location[2];
1030
1031 RNA_float_get_array(op->ptr, "location", location);
1032
1034 sima, region, powf(2.0f, 1.0f / 3.0f), location, U.uiflag & USER_ZOOM_TO_MOUSEPOS);
1035
1036 ED_region_tag_redraw(region);
1037
1038 return OPERATOR_FINISHED;
1039}
1040
1042 wmOperator *op,
1043 const wmEvent *event)
1044{
1045 ARegion *region = CTX_wm_region(C);
1046 float location[2];
1047
1049 &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
1050 RNA_float_set_array(op->ptr, "location", location);
1051
1052 return image_view_zoom_in_exec(C, op);
1053}
1054
1056{
1057 PropertyRNA *prop;
1058
1059 /* identifiers */
1060 ot->name = "Zoom In";
1061 ot->idname = "IMAGE_OT_view_zoom_in";
1062 ot->description = "Zoom in the image (centered around 2D cursor)";
1063
1064 /* API callbacks. */
1065 ot->invoke = image_view_zoom_in_invoke;
1068
1069 /* flags */
1070 ot->flag = OPTYPE_LOCK_BYPASS;
1071
1072 /* properties */
1073 prop = RNA_def_float_vector(ot->srna,
1074 "location",
1075 2,
1076 nullptr,
1077 -FLT_MAX,
1078 FLT_MAX,
1079 "Location",
1080 "Cursor location in screen coordinates",
1081 -10.0f,
1082 10.0f);
1084}
1085
1087{
1089 ARegion *region = CTX_wm_region(C);
1090 float location[2];
1091
1092 RNA_float_get_array(op->ptr, "location", location);
1093
1095 sima, region, powf(0.5f, 1.0f / 3.0f), location, U.uiflag & USER_ZOOM_TO_MOUSEPOS);
1096
1097 ED_region_tag_redraw(region);
1098
1099 return OPERATOR_FINISHED;
1100}
1101
1103 wmOperator *op,
1104 const wmEvent *event)
1105{
1106 ARegion *region = CTX_wm_region(C);
1107 float location[2];
1108
1110 &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
1111 RNA_float_set_array(op->ptr, "location", location);
1112
1113 return image_view_zoom_out_exec(C, op);
1114}
1115
1117{
1118 PropertyRNA *prop;
1119
1120 /* identifiers */
1121 ot->name = "Zoom Out";
1122 ot->idname = "IMAGE_OT_view_zoom_out";
1123 ot->description = "Zoom out the image (centered around 2D cursor)";
1124
1125 /* API callbacks. */
1129
1130 /* flags */
1131 ot->flag = OPTYPE_LOCK_BYPASS;
1132
1133 /* properties */
1134 prop = RNA_def_float_vector(ot->srna,
1135 "location",
1136 2,
1137 nullptr,
1138 -FLT_MAX,
1139 FLT_MAX,
1140 "Location",
1141 "Cursor location in screen coordinates",
1142 -10.0f,
1143 10.0f);
1145}
1146
1148
1149/* -------------------------------------------------------------------- */
1152
1154{
1156 ARegion *region = CTX_wm_region(C);
1157
1158 sima_zoom_set(sima, region, RNA_float_get(op->ptr, "ratio"), nullptr, false);
1159
1160 /* ensure pixel exact locations for draw */
1161 sima->xof = int(sima->xof);
1162 sima->yof = int(sima->yof);
1163
1164 ED_region_tag_redraw(region);
1165
1166 return OPERATOR_FINISHED;
1167}
1168
1170{
1171 /* identifiers */
1172 ot->name = "View Zoom Ratio";
1173 ot->idname = "IMAGE_OT_view_zoom_ratio";
1174 ot->description = "Set zoom ratio of the view";
1175
1176 /* API callbacks. */
1179
1180 /* flags */
1181 ot->flag = OPTYPE_LOCK_BYPASS;
1182
1183 /* properties */
1184 RNA_def_float(ot->srna,
1185 "ratio",
1186 0.0f,
1187 -FLT_MAX,
1188 FLT_MAX,
1189 "Ratio",
1190 "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out",
1191 -FLT_MAX,
1192 FLT_MAX);
1193}
1194
1196
1197/* -------------------------------------------------------------------- */
1200
1202{
1204 ARegion *region = CTX_wm_region(C);
1205 rctf bounds;
1206 const bool zoom_in = !RNA_boolean_get(op->ptr, "zoom_out");
1207
1209
1211
1212 struct {
1213 float xof;
1214 float yof;
1215 float zoom;
1216 } sima_view_prev{};
1217 sima_view_prev.xof = sima->xof;
1218 sima_view_prev.yof = sima->yof;
1219 sima_view_prev.zoom = sima->zoom;
1220
1221 sima_zoom_set_from_bounds(sima, region, &bounds);
1222
1223 /* zoom out */
1224 if (!zoom_in) {
1225 sima->xof = sima_view_prev.xof + (sima->xof - sima_view_prev.xof);
1226 sima->yof = sima_view_prev.yof + (sima->yof - sima_view_prev.yof);
1227 sima->zoom = sima_view_prev.zoom * (sima_view_prev.zoom / sima->zoom);
1228 }
1229
1230 ED_region_tag_redraw(region);
1231
1232 return OPERATOR_FINISHED;
1233}
1234
1236{
1237 /* identifiers */
1238 ot->name = "Zoom to Border";
1239 ot->description = "Zoom in the view to the nearest item contained in the border";
1240 ot->idname = "IMAGE_OT_view_zoom_border";
1241
1242 /* API callbacks. */
1243 ot->invoke = WM_gesture_box_invoke;
1245 ot->modal = WM_gesture_box_modal;
1246 ot->cancel = WM_gesture_box_cancel;
1247
1249
1250 /* rna */
1252}
1253
1254/* load/replace/save callbacks */
1255static void image_filesel(bContext *C, wmOperator *op, const char *path)
1256{
1257 RNA_string_set(op->ptr, "filepath", path);
1259}
1260
1262
1263/* -------------------------------------------------------------------- */
1266
1272
1274{
1275 ImageOpenData *iod;
1276 op->customdata = iod = MEM_new<ImageOpenData>(__func__);
1277 iod->iuser = static_cast<ImageUser *>(
1278 CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data);
1280}
1281
1282static void image_open_cancel(bContext * /*C*/, wmOperator *op)
1283{
1284 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1285 op->customdata = nullptr;
1286 MEM_delete(iod);
1287}
1288
1290 Library *owner_library,
1291 wmOperator *op,
1292 const ImageFrameRange *range,
1293 const bool use_multiview)
1294{
1295 bool exists = false;
1296 Image *ima = nullptr;
1297
1298 errno = 0;
1299 ima = BKE_image_load_exists_in_lib(bmain, owner_library, range->filepath, &exists);
1300
1301 if (!ima) {
1302 if (op->customdata) {
1303 MEM_delete(static_cast<ImageOpenData *>(op->customdata));
1304 }
1305 BKE_reportf(op->reports,
1306 RPT_ERROR,
1307 "Cannot read '%s': %s",
1308 range->filepath,
1309 errno ? strerror(errno) : RPT_("unsupported image format"));
1310 return nullptr;
1311 }
1312
1313 /* If image already exists, update its file path based on relative path property, see: #109561.
1314 */
1315 if (exists) {
1316 STRNCPY(ima->filepath, range->filepath);
1317 return ima;
1318 }
1319
1320 /* handle multiview images */
1321 if (use_multiview) {
1322 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1323 ImageFormatData *imf = &iod->im_format;
1324
1325 ima->flag |= IMA_USE_VIEWS;
1326 ima->views_format = imf->views_format;
1327 *ima->stereo3d_format = imf->stereo3d_format;
1328 }
1329 else {
1330 ima->flag &= ~IMA_USE_VIEWS;
1332 }
1333
1334 if (ima->source == IMA_SRC_FILE) {
1335 if (range->udims_detected && range->udim_tiles.first) {
1336 ima->source = IMA_SRC_TILED;
1337 ImageTile *first_tile = static_cast<ImageTile *>(ima->tiles.first);
1338 first_tile->tile_number = range->offset;
1339 LISTBASE_FOREACH (LinkData *, node, &range->udim_tiles) {
1340 BKE_image_add_tile(ima, POINTER_AS_INT(node->data), nullptr);
1341 }
1342 }
1343 else if (range->length > 1) {
1344 ima->source = IMA_SRC_SEQUENCE;
1345 }
1346 }
1347
1348 return ima;
1349}
1350
1352{
1353 Main *bmain = CTX_data_main(C);
1354 ScrArea *area = CTX_wm_area(C);
1355 Scene *scene = CTX_data_scene(C);
1356 ImageUser *iuser = nullptr;
1357 Image *ima = nullptr;
1358 int frame_seq_len = 0;
1359 int frame_ofs = 1;
1360
1361 const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
1362 const bool use_udim = RNA_boolean_get(op->ptr, "use_udim_detecting");
1363
1364 if (!op->customdata) {
1365 image_open_init(C, op);
1366 }
1367
1368 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1369 ID *owner_id = iod->pprop.ptr.owner_id;
1370 Library *owner_library = owner_id ? owner_id->lib : nullptr;
1371 blender::StringRefNull blendfile_path = BKE_main_blendfile_path(bmain);
1372 blender::StringRefNull root_path = owner_library ? owner_library->runtime->filepath_abs :
1373 blendfile_path;
1374
1375 ListBase ranges = ED_image_filesel_detect_sequences(blendfile_path, root_path, op, use_udim);
1376 LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) {
1377 Image *ima_range = image_open_single(bmain, owner_library, op, range, use_multiview);
1378
1379 /* take the first image */
1380 if ((ima == nullptr) && ima_range) {
1381 ima = ima_range;
1382 frame_seq_len = range->length;
1383 frame_ofs = range->offset;
1384 }
1385
1386 BLI_freelistN(&range->udim_tiles);
1387 BLI_freelistN(&range->frames);
1388 }
1389 BLI_freelistN(&ranges);
1390
1391 if (ima == nullptr) {
1392 return OPERATOR_CANCELLED;
1393 }
1394
1395 /* hook into UI */
1396 if (iod->pprop.prop) {
1397 /* when creating new ID blocks, use is already 1, but RNA
1398 * pointer use also increases user, so this compensates it */
1399 id_us_min(&ima->id);
1400
1401 if (iod->pprop.ptr.owner_id) {
1402 BKE_id_move_to_same_lib(*bmain, ima->id, *iod->pprop.ptr.owner_id);
1403 }
1404
1405 PointerRNA imaptr = RNA_id_pointer_create(&ima->id);
1406 RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr, nullptr);
1407 RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
1408 }
1409
1410 if (iod->iuser) {
1411 iuser = iod->iuser;
1412 }
1413 else if (area && area->spacetype == SPACE_IMAGE) {
1414 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
1415 ED_space_image_set(bmain, sima, ima, false);
1416 iuser = &sima->iuser;
1417 }
1418 else {
1419 Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
1420 if (tex && tex->type == TEX_IMAGE) {
1421 iuser = &tex->iuser;
1422 }
1423
1424 if (iuser == nullptr) {
1425 Camera *cam = static_cast<Camera *>(
1426 CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data);
1427 if (cam) {
1428 LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
1429 if (bgpic->ima == ima) {
1430 iuser = &bgpic->iuser;
1431 break;
1432 }
1433 }
1434 }
1435 }
1436 }
1437
1438 /* initialize because of new image */
1439 if (iuser) {
1440 /* If the sequence was a tiled image, we only have one frame. */
1441 iuser->frames = (ima->source == IMA_SRC_SEQUENCE) ? frame_seq_len : 1;
1442 iuser->sfra = 1;
1443 iuser->framenr = 1;
1444 if (ima->source == IMA_SRC_MOVIE) {
1445 iuser->offset = 0;
1446 }
1447 else {
1448 iuser->offset = frame_ofs - 1;
1449 }
1450 iuser->scene = scene;
1451 BKE_image_init_imageuser(ima, iuser);
1452 }
1453
1454 /* XXX BKE_packedfile_unpack_image frees image buffers */
1456
1457 BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
1459
1460 op->customdata = nullptr;
1461 MEM_delete(iod);
1462
1463 return OPERATOR_FINISHED;
1464}
1465
1467{
1468 SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
1469 const char *path = U.textudir;
1470 Image *ima = nullptr;
1471 Scene *scene = CTX_data_scene(C);
1472
1473 if (sima) {
1474 ima = sima->image;
1475 }
1476
1477 if (ima == nullptr) {
1478 Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
1479 if (tex && tex->type == TEX_IMAGE) {
1480 ima = tex->ima;
1481 }
1482 }
1483
1484 if (ima == nullptr) {
1486 PropertyRNA *prop;
1487
1488 /* hook into UI */
1490
1491 if (prop) {
1492 PointerRNA oldptr;
1493 Image *oldima;
1494
1495 oldptr = RNA_property_pointer_get(&ptr, prop);
1496 oldima = (Image *)oldptr.owner_id;
1497 /* unlikely to fail but better avoid strange crash */
1498 if (oldima && GS(oldima->id.name) == ID_IM) {
1499 ima = oldima;
1500 }
1501 }
1502 }
1503
1504 if (ima) {
1505 path = ima->filepath;
1506 }
1507
1508 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1509 return image_open_exec(C, op);
1510 }
1511
1512 image_open_init(C, op);
1513
1514 /* Show multi-view save options only if scene has multi-views. */
1515 PropertyRNA *prop;
1516 prop = RNA_struct_find_property(op->ptr, "show_multiview");
1517 RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
1518
1519 image_filesel(C, op, path);
1520
1522}
1523
1525 PropertyRNA *prop,
1526 void * /*user_data*/)
1527{
1528 const char *prop_id = RNA_property_identifier(prop);
1529
1530 return !STR_ELEM(prop_id, "filepath", "directory", "filename");
1531}
1532
1533static void image_open_draw(bContext * /*C*/, wmOperator *op)
1534{
1535 uiLayout *layout = op->layout;
1536 ImageOpenData *iod = static_cast<ImageOpenData *>(op->customdata);
1537 ImageFormatData *imf = &iod->im_format;
1538
1539 /* main draw call */
1540 uiDefAutoButsRNA(layout,
1541 op->ptr,
1543 nullptr,
1544 nullptr,
1546 false);
1547
1548 /* image template */
1549 PointerRNA imf_ptr = RNA_pointer_create_discrete(nullptr, &RNA_ImageFormatSettings, imf);
1550
1551 /* multiview template */
1552 if (RNA_boolean_get(op->ptr, "show_multiview")) {
1553 uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
1554 }
1555}
1556
1558{
1560 ot->srna, "allow_path_tokens", true, "", "Allow the path to contain substitution tokens");
1562}
1563
1565{
1566 /* identifiers */
1567 ot->name = "Open Image";
1568 ot->description = "Open image";
1569 ot->idname = "IMAGE_OT_open";
1570
1571 /* API callbacks. */
1572 ot->exec = image_open_exec;
1573 ot->invoke = image_open_invoke;
1574 ot->cancel = image_open_cancel;
1575 ot->ui = image_open_draw;
1576
1577 /* flags */
1578 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1579
1580 /* properties */
1590
1592 ot->srna,
1593 "use_sequence_detection",
1594 true,
1595 "Detect Sequences",
1596 "Automatically detect animated sequences in selected images (based on file names)");
1597 RNA_def_boolean(ot->srna,
1598 "use_udim_detecting",
1599 true,
1600 "Detect UDIMs",
1601 "Detect selected UDIM files and load all matching tiles");
1602}
1603
1605
1606/* -------------------------------------------------------------------- */
1609
1611{
1612 Image *ima = static_cast<Image *>(op->customdata);
1613 if (ima == nullptr) {
1614 return OPERATOR_CANCELLED;
1615 }
1616
1617 char filepath[FILE_MAX];
1618 RNA_string_get(op->ptr, "filepath", filepath);
1619 if (BLI_path_is_rel(filepath)) {
1620 /* Relative path created by the file-browser are always relative to the current blendfile, need
1621 * to be made relative to the library blendfile path in case image is an editable linked data.
1622 */
1624 /* TODO: make this a BKE_lib_id helper (already a static function in BKE_image too), we likely
1625 * need this in more places in the future. ~~mont29 */
1626 BLI_path_rel(filepath,
1627 ID_IS_LINKED(&ima->id) ? ima->id.lib->runtime->filepath_abs :
1629 }
1630
1631 /* If loading into a tiled texture, ensure that the filename is tokenized. */
1632 if (ima->source == IMA_SRC_TILED) {
1633 BKE_image_ensure_tile_token(filepath, sizeof(filepath));
1634 }
1635
1636 PropertyRNA *imaprop;
1637 PointerRNA imaptr = RNA_id_pointer_create(&ima->id);
1638 imaprop = RNA_struct_find_property(&imaptr, "filepath");
1639
1640 RNA_property_string_set(&imaptr, imaprop, filepath);
1641 RNA_property_update(C, &imaptr, imaprop);
1642
1643 return OPERATOR_FINISHED;
1644}
1645
1647{
1648 Image *ima = image_from_context(C);
1649 if (!ima) {
1650 return OPERATOR_CANCELLED;
1651 }
1652
1653 char filepath[FILE_MAX];
1654 STRNCPY(filepath, ima->filepath);
1655 BLI_path_abs(filepath,
1656 ID_IS_LINKED(&ima->id) ? ima->id.lib->runtime->filepath_abs :
1658
1659 /* Shift+Click to open the file, Alt+Click to browse a folder in the OS's browser. */
1660 if (event->modifier & (KM_SHIFT | KM_ALT)) {
1661 wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
1662 PointerRNA props_ptr;
1663
1664 if (event->modifier & KM_ALT) {
1665 char *lslash = (char *)BLI_path_slash_rfind(filepath);
1666 if (lslash) {
1667 *lslash = '\0';
1668 }
1669 }
1670 else if (ima->source == IMA_SRC_TILED) {
1672 BKE_image_user_file_path(&iuser, ima, filepath);
1673 }
1674
1676 RNA_string_set(&props_ptr, "filepath", filepath);
1678 WM_operator_properties_free(&props_ptr);
1679
1680 return OPERATOR_CANCELLED;
1681 }
1682
1683 /* The image is typically passed to the operator via layout/button context (e.g.
1684 * #uiLayout::context_ptr_set. The File Browser doesn't support
1685 * restoring this context when calling `exec()` though, so we have to pass it the image via
1686 * custom data. */
1687 op->customdata = ima;
1688
1689 image_filesel(C, op, filepath);
1690
1692}
1693
1695{
1696 Image *ima = image_from_context(C);
1697 return (ima && ID_IS_EDITABLE(ima));
1698}
1699
1701{
1702 /* identifiers */
1703 ot->name = "Browse Image";
1704 ot->description =
1705 "Open an image file browser, hold Shift to open the file, Alt to browse containing "
1706 "directory";
1707 ot->idname = "IMAGE_OT_file_browse";
1708
1709 /* API callbacks. */
1710 ot->exec = image_file_browse_exec;
1711 ot->invoke = image_file_browse_invoke;
1712 ot->poll = image_file_browse_poll;
1713
1714 /* flags */
1715 ot->flag = OPTYPE_UNDO;
1716
1717 /* properties */
1725}
1726
1728
1729/* -------------------------------------------------------------------- */
1732
1734{
1735 Scene *scene = CTX_data_scene(C);
1736 Image *ima = image_from_context(C);
1738
1739 if (!ima || !iuser) {
1740 /* Try to get a Texture, or a SpaceImage from context... */
1741 Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
1742 if (tex && tex->type == TEX_IMAGE) {
1743 ima = tex->ima;
1744 iuser = &tex->iuser;
1745 }
1746 }
1747
1748 if (!ima || !iuser || !BKE_image_has_anim(ima)) {
1749 return OPERATOR_CANCELLED;
1750 }
1751
1752 MovieReader *anim = ((ImageAnim *)ima->anims.first)->anim;
1753 if (!anim) {
1754 return OPERATOR_CANCELLED;
1755 }
1757 BKE_image_user_frame_calc(ima, iuser, scene->r.cfra);
1758
1759 return OPERATOR_FINISHED;
1760}
1761
1763{
1764 /* identifiers */
1765 ot->name = "Match Movie Length";
1766 ot->description = "Set image's user's length to the one of this video";
1767 ot->idname = "IMAGE_OT_match_movie_length";
1768
1769 /* API callbacks. */
1770 ot->exec = image_match_len_exec;
1771
1772 /* flags */
1773 /* Don't think we need undo for that. */
1774 ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
1775}
1776
1778
1779/* -------------------------------------------------------------------- */
1782
1784{
1785 Main *bmain = CTX_data_main(C);
1787 char filepath[FILE_MAX];
1788
1789 if (!sima->image) {
1790 return OPERATOR_CANCELLED;
1791 }
1792
1793 RNA_string_get(op->ptr, "filepath", filepath);
1794
1795 /* we can't do much if the filepath is longer than FILE_MAX :/ */
1796 STRNCPY(sima->image->filepath, filepath);
1797
1798 if (sima->image->source == IMA_SRC_GENERATED) {
1799 sima->image->source = IMA_SRC_FILE;
1800 BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_SRC_CHANGE);
1801 }
1802
1804 sima->image->source = IMA_SRC_MOVIE;
1805 }
1806 else {
1807 sima->image->source = IMA_SRC_FILE;
1808 }
1809
1810 /* XXX BKE_packedfile_unpack_image frees image buffers */
1812
1814 BKE_image_signal(bmain, sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1815 DEG_id_tag_update(&sima->image->id, 0);
1817
1818 return OPERATOR_FINISHED;
1819}
1820
1822 wmOperator *op,
1823 const wmEvent * /*event*/)
1824{
1826
1827 if (!sima->image) {
1828 return OPERATOR_CANCELLED;
1829 }
1830
1831 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1832 return image_replace_exec(C, op);
1833 }
1834
1835 if (!RNA_struct_property_is_set(op->ptr, "relative_path")) {
1836 RNA_boolean_set(op->ptr, "relative_path", BLI_path_is_rel(sima->image->filepath));
1837 }
1838
1839 image_filesel(C, op, sima->image->filepath);
1840
1842}
1843
1845{
1846 /* identifiers */
1847 ot->name = "Replace Image";
1848 ot->idname = "IMAGE_OT_replace";
1849 ot->description = "Replace current image by another one from disk";
1850
1851 /* API callbacks. */
1852 ot->exec = image_replace_exec;
1853 ot->invoke = image_replace_invoke;
1854 ot->poll = image_not_packed_poll;
1855
1856 /* flags */
1857 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1858
1859 /* properties */
1867}
1868
1870
1871/* -------------------------------------------------------------------- */
1874
1880
1882{
1883 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
1884 RNA_string_get(op->ptr, "filepath", opts->filepath);
1886 }
1887
1888 opts->relative = (RNA_struct_find_property(op->ptr, "relative_path") &&
1889 RNA_boolean_get(op->ptr, "relative_path"));
1890 opts->save_copy = (RNA_struct_find_property(op->ptr, "copy") &&
1891 RNA_boolean_get(op->ptr, "copy"));
1892 opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
1893 RNA_boolean_get(op->ptr, "save_as_render"));
1894}
1895
1896static bool save_image_op(
1897 Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, const ImageSaveOptions *opts)
1898{
1899 WM_cursor_wait(true);
1900
1901 bool ok = BKE_image_save(op->reports, bmain, ima, iuser, opts);
1902
1903 WM_cursor_wait(false);
1904
1905 /* Remember file path for next save. */
1906 STRNCPY(G.filepath_last_image, opts->filepath);
1907
1909
1910 return ok;
1911}
1912
1914{
1915 Main *bmain = CTX_data_main(C);
1916 Image *image = image_from_context(C);
1918 Scene *scene = CTX_data_scene(C);
1919
1921 isd->image = image;
1922 isd->iuser = iuser;
1923
1924 if (!BKE_image_save_options_init(&isd->opts, bmain, scene, image, iuser, true, false)) {
1926 MEM_freeN(isd);
1927 return nullptr;
1928 }
1929
1930 isd->opts.do_newpath = true;
1931
1932 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
1933 RNA_string_set(op->ptr, "filepath", isd->opts.filepath);
1934 }
1935
1936 /* Enable save_copy by default for render results. */
1937 if (image->source == IMA_SRC_VIEWER && !RNA_struct_property_is_set(op->ptr, "copy")) {
1938 RNA_boolean_set(op->ptr, "copy", true);
1939 }
1940
1941 if (!RNA_struct_property_is_set(op->ptr, "save_as_render")) {
1942 RNA_boolean_set(op->ptr, "save_as_render", isd->opts.save_as_render);
1943 }
1944
1945 /* Show multi-view save options only if image has multi-views. */
1946 PropertyRNA *prop;
1947 prop = RNA_struct_find_property(op->ptr, "show_multiview");
1949 prop = RNA_struct_find_property(op->ptr, "use_multiview");
1951
1952 op->customdata = isd;
1953
1954 return isd;
1955}
1956
1958{
1959 if (op->customdata) {
1960 ImageSaveData *isd = static_cast<ImageSaveData *>(op->customdata);
1962
1963 MEM_freeN(isd);
1964 op->customdata = nullptr;
1965 }
1966}
1967
1969{
1970 Main *bmain = CTX_data_main(C);
1971 ImageSaveData *isd;
1972
1973 if (op->customdata) {
1974 isd = static_cast<ImageSaveData *>(op->customdata);
1975 }
1976 else {
1977 isd = image_save_as_init(C, op);
1978 if (isd == nullptr) {
1979 return OPERATOR_CANCELLED;
1980 }
1981 }
1982
1983 image_save_options_from_op(bmain, &isd->opts, op);
1985
1986 save_image_op(bmain, isd->image, isd->iuser, op, &isd->opts);
1987
1988 if (isd->opts.save_copy == false) {
1990 }
1991
1993
1994 return OPERATOR_FINISHED;
1995}
1996
1998{
1999 Main *bmain = CTX_data_main(C);
2000 ImageSaveData *isd = static_cast<ImageSaveData *>(op->customdata);
2001
2002 image_save_options_from_op(bmain, &isd->opts, op);
2004
2006}
2007
2009 wmOperator *op,
2010 const wmEvent * /*event*/)
2011{
2012 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
2013 return image_save_as_exec(C, op);
2014 }
2015
2017 if (isd == nullptr) {
2018 return OPERATOR_CANCELLED;
2019 }
2020
2021 image_filesel(C, op, isd->opts.filepath);
2022
2024}
2025
2027{
2029}
2030
2031static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *user_data)
2032{
2033 ImageSaveData *isd = static_cast<ImageSaveData *>(user_data);
2034 const char *prop_id = RNA_property_identifier(prop);
2035
2036 return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
2037 STREQ(prop_id, "filename") ||
2038 /* when saving a copy, relative path has no effect */
2039 (STREQ(prop_id, "relative_path") && RNA_boolean_get(ptr, "copy")) ||
2040 (STREQ(prop_id, "save_as_render") && isd->image->source == IMA_SRC_VIEWER));
2041}
2042
2044{
2045 uiLayout *layout = op->layout;
2046 ImageSaveData *isd = static_cast<ImageSaveData *>(op->customdata);
2047 const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
2048 const bool save_as_render = RNA_boolean_get(op->ptr, "save_as_render");
2049
2050 layout->use_property_split_set(true);
2051 layout->use_property_decorate_set(false);
2052
2053 /* Operator settings. */
2054 uiDefAutoButsRNA(layout,
2055 op->ptr,
2057 isd,
2058 nullptr,
2060 false);
2061
2062 layout->separator();
2063
2064 /* Image format settings. */
2066 nullptr, &RNA_ImageFormatSettings, &isd->opts.im_format);
2067 uiTemplateImageSettings(layout, C, &imf_ptr, save_as_render);
2068
2069 if (!save_as_render) {
2070 PointerRNA linear_settings_ptr = RNA_pointer_get(&imf_ptr, "linear_colorspace_settings");
2071 uiLayout *col = &layout->column(true);
2072 col->separator();
2073 col->prop(&linear_settings_ptr, "name", UI_ITEM_NONE, IFACE_("Color Space"), ICON_NONE);
2074 }
2075
2076 /* Multiview settings. */
2077 if (is_multiview) {
2078 uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
2079 }
2080}
2081
2083{
2085 return false;
2086 }
2087
2088 if (G.is_rendering) {
2089 /* no need to nullptr check here */
2090 Image *ima = image_from_context(C);
2091
2092 if (ima->source == IMA_SRC_VIEWER) {
2093 CTX_wm_operator_poll_msg_set(C, "Cannot save image while rendering");
2094 return false;
2095 }
2096 }
2097
2098 return true;
2099}
2100
2102{
2103 /* identifiers */
2104 ot->name = "Save As Image";
2105 ot->idname = "IMAGE_OT_save_as";
2106 ot->description = "Save the image with another name and/or settings";
2107
2108 /* API callbacks. */
2109 ot->exec = image_save_as_exec;
2110 ot->check = image_save_as_check;
2111 ot->invoke = image_save_as_invoke;
2112 ot->cancel = image_save_as_cancel;
2113 ot->ui = image_save_as_draw;
2114 ot->poll = image_save_as_poll;
2115
2116 /* flags */
2117 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2118
2119 /* properties */
2120 PropertyRNA *prop;
2121 prop = RNA_def_boolean(
2122 ot->srna,
2123 "save_as_render",
2124 false,
2125 "Save As Render",
2126 "Save image with render color management.\n"
2127 "For display image formats like PNG, apply view and display transform.\n"
2128 "For intermediate image formats like OpenEXR, use the default render output color space");
2130 prop = RNA_def_boolean(ot->srna,
2131 "copy",
2132 false,
2133 "Copy",
2134 "Create a new image file without modifying the current image in Blender");
2136
2141 FILE_SAVE,
2145}
2146
2148
2149/* -------------------------------------------------------------------- */
2152
2157{
2158 void *lock;
2159 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
2160 bool ret = false;
2161
2162 if (ibuf && BKE_image_buffer_format_writable(ibuf)) {
2163 ret = true;
2164 }
2165
2166 BKE_image_release_ibuf(ima, ibuf, lock);
2167 return ret;
2168}
2169
2171{
2172 /* Can't save if there are no pixels. */
2173 if (image_from_context_has_data_poll(C) == false) {
2174 return false;
2175 }
2176
2177 /* Check if there is a valid file path and image format we can write
2178 * outside of the 'poll' so we can show a report with a pop-up. */
2179
2180 /* Can always repack images.
2181 * Images without a filepath will go to "Save As". */
2182 return true;
2183}
2184
2186{
2187 Main *bmain = CTX_data_main(C);
2188 Image *image = image_from_context(C);
2190 Scene *scene = CTX_data_scene(C);
2191 ImageSaveOptions opts;
2192 bool ok = false;
2193
2194 if (BKE_image_has_packedfile(image)) {
2195 /* Save packed files to memory. */
2196 BKE_image_memorypack(image);
2197 /* Report since this can be called from key shortcuts. */
2198 BKE_reportf(op->reports, RPT_INFO, "Packed to memory image \"%s\"", image->filepath);
2199 return OPERATOR_FINISHED;
2200 }
2201
2202 if (!BKE_image_save_options_init(&opts, bmain, scene, image, iuser, false, false)) {
2204 return OPERATOR_CANCELLED;
2205 }
2206 image_save_options_from_op(bmain, &opts, op);
2207
2208 /* Check if file write permission is ok. */
2209 if (BLI_exists(opts.filepath) && !BLI_file_is_writable(opts.filepath)) {
2211 op->reports, RPT_ERROR, "Cannot save image, path \"%s\" is not writable", opts.filepath);
2212 }
2213 else if (save_image_op(bmain, image, iuser, op, &opts)) {
2214 /* Report since this can be called from key shortcuts. */
2215 BKE_reportf(op->reports, RPT_INFO, "Saved image \"%s\"", opts.filepath);
2216 ok = true;
2217 }
2218
2220
2221 if (ok) {
2222 return OPERATOR_FINISHED;
2223 }
2224
2225 return OPERATOR_CANCELLED;
2226}
2227
2229{
2230 Image *ima = image_from_context(C);
2232
2233 /* Not writable formats or images without a file-path will go to "Save As". */
2234 if (!BKE_image_has_packedfile(ima) &&
2235 (!BKE_image_has_filepath(ima) || !image_file_format_writable(ima, iuser)))
2236 {
2238 C, "IMAGE_OT_save_as", blender::wm::OpCallContext::InvokeDefault, nullptr, event);
2239 return OPERATOR_CANCELLED;
2240 }
2241 return image_save_exec(C, op);
2242}
2243
2245{
2246 /* identifiers */
2247 ot->name = "Save Image";
2248 ot->idname = "IMAGE_OT_save";
2249 ot->description = "Save the image with current name and settings";
2250
2251 /* API callbacks. */
2252 ot->exec = image_save_exec;
2253 ot->invoke = image_save_invoke;
2254 ot->poll = image_save_poll;
2255
2256 /* flags */
2257 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2258}
2259
2261
2262/* -------------------------------------------------------------------- */
2265
2267{
2268 Image *image = image_from_context(C);
2269 ImBuf *ibuf, *first_ibuf = nullptr;
2270 int tot = 0;
2271 char di[FILE_MAX];
2272 MovieCacheIter *iter;
2273
2274 if (image == nullptr) {
2275 return OPERATOR_CANCELLED;
2276 }
2277
2278 if (image->source != IMA_SRC_SEQUENCE) {
2279 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
2280 return OPERATOR_CANCELLED;
2281 }
2282
2283 if (image->type == IMA_TYPE_MULTILAYER) {
2284 BKE_report(op->reports, RPT_ERROR, "Cannot save multilayer sequences");
2285 return OPERATOR_CANCELLED;
2286 }
2287
2288 /* get total dirty buffers and first dirty buffer which is used for menu */
2289 ibuf = nullptr;
2290 if (image->cache != nullptr) {
2291 iter = IMB_moviecacheIter_new(image->cache);
2292 while (!IMB_moviecacheIter_done(iter)) {
2293 ibuf = IMB_moviecacheIter_getImBuf(iter);
2294 if (ibuf != nullptr && ibuf->userflags & IB_BITMAPDIRTY) {
2295 if (first_ibuf == nullptr) {
2296 first_ibuf = ibuf;
2297 }
2298 tot++;
2299 }
2301 }
2303 }
2304
2305 if (tot == 0) {
2306 BKE_report(op->reports, RPT_WARNING, "No images have been changed");
2307 return OPERATOR_CANCELLED;
2308 }
2309
2310 /* get a filename for menu */
2311 BLI_path_split_dir_part(first_ibuf->filepath, di, sizeof(di));
2312 BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
2313
2314 iter = IMB_moviecacheIter_new(image->cache);
2315 while (!IMB_moviecacheIter_done(iter)) {
2316 ibuf = IMB_moviecacheIter_getImBuf(iter);
2317
2318 if (ibuf != nullptr && ibuf->userflags & IB_BITMAPDIRTY) {
2319 if (0 == IMB_save_image(ibuf, ibuf->filepath, IB_byte_data)) {
2320 BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
2321 break;
2322 }
2323
2324 BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->filepath);
2325 ibuf->userflags &= ~IB_BITMAPDIRTY;
2326 }
2327
2329 }
2331
2332 return OPERATOR_FINISHED;
2333}
2334
2336{
2337 /* identifiers */
2338 ot->name = "Save Sequence";
2339 ot->idname = "IMAGE_OT_save_sequence";
2340 ot->description = "Save a sequence of images";
2341
2342 /* API callbacks. */
2345
2346 /* flags */
2347 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2348}
2349
2351
2352/* -------------------------------------------------------------------- */
2355
2360
2361static bool image_should_be_saved(Image *ima, bool *r_is_format_writable)
2362{
2363 if (BKE_image_is_dirty_writable(ima, r_is_format_writable) &&
2365 {
2367 }
2368 return false;
2369}
2370
2372{
2373 return strchr(ima->filepath, '\\') || strchr(ima->filepath, '/');
2374}
2375
2377{
2378 /* Images without a filepath (implied with IMA_SRC_GENERATED) should
2379 * be packed during a save_all operation. */
2380 return (ima->source == IMA_SRC_GENERATED) ||
2381 (ima->source == IMA_SRC_TILED && !BKE_image_has_filepath(ima));
2382}
2383
2385{
2386 ReportList reports;
2387 BKE_reports_init(&reports, RPT_STORE);
2388
2389 uint modified_images_count = ED_image_save_all_modified_info(bmain, &reports);
2390 bool should_save = modified_images_count || !BLI_listbase_is_empty(&reports.list);
2391
2392 BKE_reports_free(&reports);
2393
2394 return should_save;
2395}
2396
2398{
2399 blender::Set<std::string> unique_paths;
2400
2401 int num_saveable_images = 0;
2402
2403 for (Image *ima = static_cast<Image *>(bmain->images.first); ima;
2404 ima = static_cast<Image *>(ima->id.next))
2405 {
2406 bool is_format_writable;
2407
2408 if (image_should_be_saved(ima, &is_format_writable)) {
2410 if (ID_IS_EDITABLE(ima)) {
2411 num_saveable_images++;
2412 }
2413 else {
2414 BKE_reportf(reports,
2416 "Packed library image cannot be saved: \"%s\" from \"%s\"",
2417 ima->id.name + 2,
2418 ima->id.lib->filepath);
2419 }
2420 }
2421 else if (!is_format_writable) {
2422 BKE_reportf(reports,
2424 "Image cannot be saved, use a different file format: \"%s\"",
2425 ima->id.name + 2);
2426 }
2427 else {
2428 if (image_has_valid_path(ima)) {
2429 num_saveable_images++;
2430 if (unique_paths.contains_as(ima->filepath)) {
2431 BKE_reportf(reports,
2433 "Multiple images cannot be saved to an identical path: \"%s\"",
2434 ima->filepath);
2435 }
2436 else {
2437 unique_paths.add(ima->filepath);
2438 }
2439 }
2440 else {
2441 BKE_reportf(reports,
2443 "Image cannot be saved, no valid file path: \"%s\"",
2444 ima->filepath);
2445 }
2446 }
2447 }
2448 }
2449
2450 return num_saveable_images;
2451}
2452
2454{
2455 Main *bmain = CTX_data_main(C);
2456
2457 ED_image_save_all_modified_info(bmain, reports);
2458
2459 bool ok = true;
2460
2461 for (Image *ima = static_cast<Image *>(bmain->images.first); ima;
2462 ima = static_cast<Image *>(ima->id.next))
2463 {
2464 bool is_format_writable;
2465
2466 if (image_should_be_saved(ima, &is_format_writable)) {
2469 }
2470 else if (is_format_writable) {
2471 if (image_has_valid_path(ima)) {
2472 ImageSaveOptions opts;
2473 Scene *scene = CTX_data_scene(C);
2474 if (BKE_image_save_options_init(&opts, bmain, scene, ima, nullptr, false, false)) {
2475 bool saved_successfully = BKE_image_save(reports, bmain, ima, nullptr, &opts);
2476 ok = ok && saved_successfully;
2477 }
2479 }
2480 }
2481 }
2482 }
2483 return ok;
2484}
2485
2487{
2488 int num_files = ED_image_save_all_modified_info(CTX_data_main(C), nullptr);
2489 return num_files > 0;
2490}
2491
2497
2499{
2500 /* identifiers */
2501 ot->name = "Save All Modified";
2502 ot->idname = "IMAGE_OT_save_all_modified";
2503 ot->description = "Save all modified images";
2504
2505 /* API callbacks. */
2508
2509 /* flags */
2510 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2511}
2512
2514
2515/* -------------------------------------------------------------------- */
2518
2520{
2521 Main *bmain = CTX_data_main(C);
2522 Image *ima = image_from_context(C);
2524
2525 if (!ima) {
2526 return OPERATOR_CANCELLED;
2527 }
2528
2529 /* XXX BKE_packedfile_unpack_image frees image buffers */
2531
2532 BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD);
2533 DEG_id_tag_update(&ima->id, 0);
2535
2537
2538 return OPERATOR_FINISHED;
2539}
2540
2542{
2543 /* identifiers */
2544 ot->name = "Reload Image";
2545 ot->idname = "IMAGE_OT_reload";
2546 ot->description = "Reload current image from disk";
2547
2548 /* API callbacks. */
2549 ot->exec = image_reload_exec;
2550
2551 /* flags */
2552 ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
2553}
2554
2556
2557/* -------------------------------------------------------------------- */
2560
2561#define IMA_DEF_NAME N_("Untitled")
2562
2563enum {
2567};
2568
2572
2574{
2575 if (op->customdata) {
2576 return static_cast<ImageNewData *>(op->customdata);
2577 }
2578
2579 ImageNewData *data = MEM_new<ImageNewData>(__func__);
2580 UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2581 op->customdata = data;
2582 return data;
2583}
2584
2586{
2587 if (op->customdata) {
2588 MEM_delete(static_cast<ImageNewData *>(op->customdata));
2589 }
2590}
2591
2593{
2594 SpaceImage *sima;
2595 Image *ima;
2596 Main *bmain;
2597 PropertyRNA *prop;
2598 char name_buffer[MAX_ID_NAME - 2];
2599 const char *name;
2600 float color[4];
2601 int width, height, floatbuf, gen_type, alpha;
2602 int stereo3d;
2603
2604 /* retrieve state */
2605 sima = CTX_wm_space_image(C);
2606 bmain = CTX_data_main(C);
2607
2608 prop = RNA_struct_find_property(op->ptr, "name");
2609 RNA_property_string_get(op->ptr, prop, name_buffer);
2610 if (!RNA_property_is_set(op->ptr, prop)) {
2611 /* Default value, we can translate! */
2612 name = DATA_(name_buffer);
2613 }
2614 else {
2615 name = name_buffer;
2616 }
2617 width = RNA_int_get(op->ptr, "width");
2618 height = RNA_int_get(op->ptr, "height");
2619 floatbuf = RNA_boolean_get(op->ptr, "float");
2620 gen_type = RNA_enum_get(op->ptr, "generated_type");
2621 RNA_float_get_array(op->ptr, "color", color);
2622 alpha = RNA_boolean_get(op->ptr, "alpha");
2623 stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
2624 bool tiled = RNA_boolean_get(op->ptr, "tiled");
2625
2626 if (!alpha) {
2627 color[3] = 1.0f;
2628 }
2629
2630 ima = BKE_image_add_generated(bmain,
2631 width,
2632 height,
2633 name,
2634 alpha ? 32 : 24,
2635 floatbuf,
2636 gen_type,
2637 color,
2638 stereo3d,
2639 false,
2640 tiled);
2641
2642 if (!ima) {
2643 image_new_free(op);
2644 return OPERATOR_CANCELLED;
2645 }
2646
2647 /* hook into UI */
2649
2650 if (data->pprop.prop) {
2651 /* when creating new ID blocks, use is already 1, but RNA
2652 * pointer use also increases user, so this compensates it */
2653 id_us_min(&ima->id);
2654
2655 if (data->pprop.ptr.owner_id) {
2656 BKE_id_move_to_same_lib(*bmain, ima->id, *data->pprop.ptr.owner_id);
2657 }
2658
2659 PointerRNA imaptr = RNA_id_pointer_create(&ima->id);
2660 RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr, nullptr);
2661 RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
2662 }
2663 else if (sima) {
2664 ED_space_image_set(bmain, sima, ima, false);
2665 }
2666 else {
2667 /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to
2668 * anything. ref. #94599. */
2669 id_us_min(&ima->id);
2670 }
2671
2672 BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : nullptr, IMA_SIGNAL_USER_NEW_IMAGE);
2673
2675
2676 image_new_free(op);
2677
2678 return OPERATOR_FINISHED;
2679}
2680
2682{
2683 /* Get property in advance, it doesn't work after WM_operator_props_dialog_popup. */
2685 op->customdata = data = MEM_new<ImageNewData>(__func__);
2686 UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
2687
2688 /* Better for user feedback. */
2689 RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
2691 C, op, 300, IFACE_("Create a New Image"), IFACE_("New Image"));
2692}
2693
2694static void image_new_draw(bContext * /*C*/, wmOperator *op)
2695{
2696 uiLayout *col;
2697 uiLayout *layout = op->layout;
2698#if 0
2699 Scene *scene = CTX_data_scene(C);
2700 const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
2701#endif
2702
2703 /* copy of WM_operator_props_dialog_popup() layout */
2704
2705 layout->use_property_split_set(true);
2706 layout->use_property_decorate_set(false);
2707
2708 col = &layout->column(false);
2709 col->prop(op->ptr, "name", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2710 col->prop(op->ptr, "width", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2711 col->prop(op->ptr, "height", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2712 col->prop(op->ptr, "color", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2713 col->prop(op->ptr, "alpha", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2714 col->prop(op->ptr, "generated_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2715 col->prop(op->ptr, "float", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2716 col->prop(op->ptr, "tiled", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2717
2718#if 0
2719 if (is_multiview) {
2720 col[0].label("", ICON_NONE);
2721 col[1].prop( op->ptr, "use_stereo_3d", 0, std::nullopt, ICON_NONE);
2722 }
2723#endif
2724}
2725
2726static void image_new_cancel(bContext * /*C*/, wmOperator *op)
2727{
2728 image_new_free(op);
2729}
2730
2732{
2733 PropertyRNA *prop;
2734 static const float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2735
2736 /* identifiers */
2737 ot->name = "New Image";
2738 ot->description = "Create a new image";
2739 ot->idname = "IMAGE_OT_new";
2740
2741 /* API callbacks. */
2742 ot->exec = image_new_exec;
2743 ot->invoke = image_new_invoke;
2744 ot->ui = image_new_draw;
2745 ot->cancel = image_new_cancel;
2746
2747 /* flags */
2748 ot->flag = OPTYPE_UNDO;
2749
2750 /* properties */
2751 ot->prop = RNA_def_string(
2752 ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image data-block name");
2753 prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
2755 prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
2757 prop = RNA_def_float_color(
2758 ot->srna, "color", 4, nullptr, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
2760 RNA_def_property_float_array_default(prop, default_color);
2761 RNA_def_boolean(ot->srna, "alpha", true, "Alpha", "Create an image with an alpha channel");
2762 RNA_def_enum(ot->srna,
2763 "generated_type",
2766 "Generated Type",
2767 "Fill the image with a grid for UV map testing");
2768 RNA_def_boolean(ot->srna,
2769 "float",
2770 false,
2771 "32-bit Float",
2772 "Create image with 32-bit floating-point bit depth");
2774 prop = RNA_def_boolean(
2775 ot->srna, "use_stereo_3d", false, "Stereo 3D", "Create an image with left and right views");
2777 prop = RNA_def_boolean(ot->srna, "tiled", false, "Tiled", "Create a tiled image");
2779}
2780
2781#undef IMA_DEF_NAME
2782
2784
2785/* -------------------------------------------------------------------- */
2788
2790{
2791 Image *ima = image_from_context(C);
2793 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
2795 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
2796
2797 if (ibuf == nullptr) {
2798 /* TODO: this should actually never happen, but does for render-results -> cleanup. */
2799 return OPERATOR_CANCELLED;
2800 }
2801
2802 const bool use_flip_x = RNA_boolean_get(op->ptr, "use_flip_x");
2803 const bool use_flip_y = RNA_boolean_get(op->ptr, "use_flip_y");
2804
2805 if (!use_flip_x && !use_flip_y) {
2806 BKE_image_release_ibuf(ima, ibuf, nullptr);
2807 return OPERATOR_FINISHED;
2808 }
2809
2810 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
2811
2812 if (is_paint) {
2814 }
2815
2816 const int size_x = ibuf->x;
2817 const int size_y = ibuf->y;
2818
2819 if (ibuf->float_buffer.data) {
2820 float *float_pixels = ibuf->float_buffer.data;
2821
2822 float *orig_float_pixels = static_cast<float *>(MEM_dupallocN(float_pixels));
2823 for (int x = 0; x < size_x; x++) {
2824 const int source_pixel_x = use_flip_x ? size_x - x - 1 : x;
2825 for (int y = 0; y < size_y; y++) {
2826 const int source_pixel_y = use_flip_y ? size_y - y - 1 : y;
2827
2828 const float *source_pixel =
2829 &orig_float_pixels[4 * (source_pixel_x + source_pixel_y * size_x)];
2830 float *target_pixel = &float_pixels[4 * (x + y * size_x)];
2831
2832 copy_v4_v4(target_pixel, source_pixel);
2833 }
2834 }
2835 MEM_freeN(orig_float_pixels);
2836
2837 if (ibuf->byte_buffer.data) {
2838 IMB_byte_from_float(ibuf);
2839 }
2840 }
2841 else if (ibuf->byte_buffer.data) {
2842 uchar *char_pixels = ibuf->byte_buffer.data;
2843 uchar *orig_char_pixels = static_cast<uchar *>(MEM_dupallocN(char_pixels));
2844 for (int x = 0; x < size_x; x++) {
2845 const int source_pixel_x = use_flip_x ? size_x - x - 1 : x;
2846 for (int y = 0; y < size_y; y++) {
2847 const int source_pixel_y = use_flip_y ? size_y - y - 1 : y;
2848
2849 const uchar *source_pixel =
2850 &orig_char_pixels[4 * (source_pixel_x + source_pixel_y * size_x)];
2851 uchar *target_pixel = &char_pixels[4 * (x + y * size_x)];
2852
2853 copy_v4_v4_uchar(target_pixel, source_pixel);
2854 }
2855 }
2856 MEM_freeN(orig_char_pixels);
2857 }
2858 else {
2859 BKE_image_release_ibuf(ima, ibuf, nullptr);
2860 return OPERATOR_CANCELLED;
2861 }
2862
2864 BKE_image_mark_dirty(ima, ibuf);
2865
2867
2869
2872
2873 BKE_image_release_ibuf(ima, ibuf, nullptr);
2874
2875 return OPERATOR_FINISHED;
2876}
2877
2879{
2880 /* identifiers */
2881 ot->name = "Flip Image";
2882 ot->idname = "IMAGE_OT_flip";
2883 ot->description = "Flip the image";
2884
2885 /* API callbacks. */
2886 ot->exec = image_flip_exec;
2888
2889 /* properties */
2890 PropertyRNA *prop;
2891 prop = RNA_def_boolean(
2892 ot->srna, "use_flip_x", false, "Horizontal", "Flip the image horizontally");
2894 prop = RNA_def_boolean(ot->srna, "use_flip_y", false, "Vertical", "Flip the image vertically");
2896
2897 /* flags */
2898 ot->flag = OPTYPE_REGISTER;
2899}
2900
2902
2903/* -------------------------------------------------------------------- */
2906
2908{
2909 Image *ima = image_from_context(C);
2911 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
2913 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
2914
2915 if (ibuf == nullptr) {
2916 /* TODO: this should actually never happen, but does for render-results -> cleanup. */
2917 return OPERATOR_CANCELLED;
2918 }
2919
2920 int degrees = RNA_enum_get(op->ptr, "degrees");
2921
2922 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
2923
2924 if (is_paint) {
2926 }
2927
2928 if (!IMB_rotate_orthogonal(ibuf, degrees)) {
2929 BKE_image_release_ibuf(ima, ibuf, nullptr);
2930 return OPERATOR_CANCELLED;
2931 }
2932
2934 BKE_image_mark_dirty(ima, ibuf);
2935
2937
2939
2941
2943 BKE_image_release_ibuf(ima, ibuf, nullptr);
2944
2945 return OPERATOR_FINISHED;
2946}
2947
2949{
2950 static const EnumPropertyItem orthogonal_rotation_items[] = {
2951 {90, "90", 0, "90 Degrees", "Rotate 90 degrees clockwise"},
2952 {180, "180", 0, "180 Degrees", "Rotate 180 degrees clockwise"},
2953 {270, "270", 0, "270 Degrees", "Rotate 270 degrees clockwise"},
2954 {0, nullptr, 0, nullptr, nullptr},
2955 };
2956
2957 /* identifiers */
2958 ot->name = "Rotate Image Orthogonal";
2959 ot->idname = "IMAGE_OT_rotate_orthogonal";
2960 ot->description = "Rotate the image";
2961
2962 /* API callbacks. */
2965
2966 /* properties */
2967 PropertyRNA *prop;
2968 prop = RNA_def_enum(ot->srna,
2969 "degrees",
2970 orthogonal_rotation_items,
2971 90,
2972 "Degrees",
2973 "Amount of rotation in degrees (90, 180, 270)");
2975
2976 /* flags */
2977 ot->flag = OPTYPE_REGISTER;
2978}
2979
2981
2982/* -------------------------------------------------------------------- */
2985
2987{
2988 Scene *scene = CTX_data_scene(C);
2989 Image *ima = image_from_context(C);
2990 if (ima == nullptr) {
2991 return OPERATOR_CANCELLED;
2992 }
2993
2994 if (G.is_rendering && ima->source == IMA_SRC_VIEWER) {
2995 BKE_report(op->reports, RPT_ERROR, "Images cannot be copied while rendering");
2996 return OPERATOR_CANCELLED;
2997 }
2998
3000 WM_cursor_wait(true);
3001 void *lock;
3002 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
3003 bool changed = false;
3004 if (ibuf) {
3005 /* Clipboard uses byte buffer, so match saving an 8 bit PNG for color management. */
3006 const bool save_as_render = ima->flag & IMA_VIEW_AS_RENDER;
3007
3008 ImageFormatData image_format;
3009 BKE_image_format_init_for_write(&image_format, scene, nullptr);
3010 BKE_image_format_set(&image_format, nullptr, R_IMF_IMTYPE_PNG);
3011 image_format.depth = R_IMF_CHAN_DEPTH_8;
3012
3013 ImBuf *colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
3014 ibuf, save_as_render, true, &image_format);
3015
3016 if (WM_clipboard_image_set_byte_buffer(colormanaged_ibuf)) {
3017 changed = true;
3018 }
3019
3020 if (colormanaged_ibuf != ibuf) {
3021 IMB_freeImBuf(colormanaged_ibuf);
3022 }
3023 BKE_image_format_free(&image_format);
3024 }
3025 BKE_image_release_ibuf(ima, ibuf, lock);
3026 WM_cursor_wait(false);
3027
3028 return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3029}
3030
3032{
3034 CTX_wm_operator_poll_msg_set(C, "No images available");
3035 return false;
3036 }
3037
3038 return true;
3039}
3040
3042{
3043 /* identifiers */
3044 ot->name = "Copy Image";
3045 ot->idname = "IMAGE_OT_clipboard_copy";
3046 ot->description = "Copy the image to the clipboard";
3047
3048 /* API callbacks. */
3051
3052 /* flags */
3053 ot->flag = OPTYPE_REGISTER;
3054}
3055
3057
3058/* -------------------------------------------------------------------- */
3061
3063{
3064 bool changed = false;
3065
3066 WM_cursor_wait(true);
3067 ImBuf *ibuf = WM_clipboard_image_get();
3068 if (ibuf) {
3069 ED_undo_push_op(C, op);
3070
3071 Main *bmain = CTX_data_main(C);
3073 Image *ima = BKE_image_add_from_imbuf(bmain, ibuf, "Clipboard");
3074 IMB_freeImBuf(ibuf);
3075
3076 ED_space_image_set(bmain, sima, ima, false);
3077 BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : nullptr, IMA_SIGNAL_USER_NEW_IMAGE);
3079 changed = true;
3080 }
3081 WM_cursor_wait(false);
3082
3083 return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3084}
3085
3087{
3089 if (!sima) {
3090 CTX_wm_operator_poll_msg_set(C, "Image Editor not found");
3091 return false;
3092 }
3093
3095 CTX_wm_operator_poll_msg_set(C, "No compatible images are on the clipboard");
3096 return false;
3097 }
3098
3099 return true;
3100}
3101
3103{
3104 /* identifiers */
3105 ot->name = "Paste Image";
3106 ot->idname = "IMAGE_OT_clipboard_paste";
3107 ot->description = "Paste new image from the clipboard";
3108
3109 /* API callbacks. */
3112
3113 /* flags */
3114 ot->flag = OPTYPE_REGISTER;
3115}
3116
3118
3119/* -------------------------------------------------------------------- */
3122
3124{
3125 Image *ima = image_from_context(C);
3127 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3129 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
3130
3131 /* flags indicate if this channel should be inverted */
3132 const bool r = RNA_boolean_get(op->ptr, "invert_r");
3133 const bool g = RNA_boolean_get(op->ptr, "invert_g");
3134 const bool b = RNA_boolean_get(op->ptr, "invert_b");
3135 const bool a = RNA_boolean_get(op->ptr, "invert_a");
3136
3137 size_t i;
3138
3139 if (ibuf == nullptr) {
3140 /* TODO: this should actually never happen, but does for render-results -> cleanup */
3141 return OPERATOR_CANCELLED;
3142 }
3143
3144 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
3145
3146 if (is_paint) {
3148 }
3149
3150 /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
3151 if (ibuf->float_buffer.data) {
3152
3153 float *fp = ibuf->float_buffer.data;
3154 for (i = size_t(ibuf->x) * ibuf->y; i > 0; i--, fp += 4) {
3155 if (r) {
3156 fp[0] = 1.0f - fp[0];
3157 }
3158 if (g) {
3159 fp[1] = 1.0f - fp[1];
3160 }
3161 if (b) {
3162 fp[2] = 1.0f - fp[2];
3163 }
3164 if (a) {
3165 fp[3] = 1.0f - fp[3];
3166 }
3167 }
3168
3169 if (ibuf->byte_buffer.data) {
3170 IMB_byte_from_float(ibuf);
3171 }
3172 }
3173 else if (ibuf->byte_buffer.data) {
3174
3175 uchar *cp = ibuf->byte_buffer.data;
3176 for (i = size_t(ibuf->x) * ibuf->y; i > 0; i--, cp += 4) {
3177 if (r) {
3178 cp[0] = 255 - cp[0];
3179 }
3180 if (g) {
3181 cp[1] = 255 - cp[1];
3182 }
3183 if (b) {
3184 cp[2] = 255 - cp[2];
3185 }
3186 if (a) {
3187 cp[3] = 255 - cp[3];
3188 }
3189 }
3190 }
3191 else {
3192 BKE_image_release_ibuf(ima, ibuf, nullptr);
3193 return OPERATOR_CANCELLED;
3194 }
3195
3197 BKE_image_mark_dirty(ima, ibuf);
3198
3200
3202
3204
3206
3207 BKE_image_release_ibuf(ima, ibuf, nullptr);
3208
3209 return OPERATOR_FINISHED;
3210}
3211
3213{
3214 PropertyRNA *prop;
3215
3216 /* identifiers */
3217 ot->name = "Invert Channels";
3218 ot->idname = "IMAGE_OT_invert";
3219 ot->description = "Invert image's channels";
3220
3221 /* API callbacks. */
3222 ot->exec = image_invert_exec;
3224
3225 /* properties */
3226 prop = RNA_def_boolean(ot->srna, "invert_r", false, "Red", "Invert red channel");
3228 prop = RNA_def_boolean(ot->srna, "invert_g", false, "Green", "Invert green channel");
3230 prop = RNA_def_boolean(ot->srna, "invert_b", false, "Blue", "Invert blue channel");
3232 prop = RNA_def_boolean(ot->srna, "invert_a", false, "Alpha", "Invert alpha channel");
3234
3235 /* flags */
3236 ot->flag = OPTYPE_REGISTER;
3237}
3238
3240
3241/* -------------------------------------------------------------------- */
3244
3246{
3247 Image *ima = image_from_context(C);
3249 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
3250 if (!RNA_property_is_set(op->ptr, prop)) {
3251 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3252 const int size[2] = {ibuf->x, ibuf->y};
3254 BKE_image_release_ibuf(ima, ibuf, nullptr);
3255 }
3257 C, op, 200, IFACE_("Scale Image to New Size"), IFACE_("Resize"));
3258}
3259
3261{
3262 Image *ima = image_from_context(C);
3265 const bool is_paint = ((sima != nullptr) && (sima->mode == SI_MODE_PAINT));
3266
3267 if (is_paint) {
3269 }
3270
3271 const bool is_scaling_all = RNA_boolean_get(op->ptr, "all_udims");
3272
3273 if (!is_scaling_all) {
3274 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3275
3276 if (ibuf == nullptr) {
3277 /* TODO: this should actually never happen, but does for render-results -> cleanup */
3278 return OPERATOR_CANCELLED;
3279 }
3280
3281 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
3282 int size[2];
3283 if (RNA_property_is_set(op->ptr, prop)) {
3285 }
3286 else {
3287 size[0] = ibuf->x;
3288 size[1] = ibuf->y;
3290 }
3291
3292 ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
3294 IMB_scale(ibuf, size[0], size[1], IMBScaleFilter::Box, false);
3295 BKE_image_mark_dirty(ima, ibuf);
3296 BKE_image_release_ibuf(ima, ibuf, nullptr);
3298 }
3299 else {
3300 // Ensure that an image buffer can be acquired for all UDIM tiles
3301 LISTBASE_FOREACH (ImageTile *, current_tile, &ima->tiles) {
3302 iuser.tile = current_tile->tile_number;
3303
3304 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3305
3306 if (ibuf == nullptr) {
3307 /* TODO: this should actually never happen, but does for render-results -> cleanup */
3308 return OPERATOR_CANCELLED;
3309 }
3310
3311 BKE_image_release_ibuf(ima, ibuf, nullptr);
3312 }
3313
3315 LISTBASE_FOREACH (ImageTile *, current_tile, &ima->tiles) {
3316 iuser.tile = current_tile->tile_number;
3317
3318 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
3319
3320 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
3321 int size[2];
3322 if (RNA_property_is_set(op->ptr, prop)) {
3324 }
3325 else {
3326 size[0] = ibuf->x;
3327 size[1] = ibuf->y;
3329 }
3330
3332 IMB_scale(ibuf, size[0], size[1], IMBScaleFilter::Box, false);
3333 BKE_image_mark_dirty(ima, ibuf);
3334 BKE_image_release_ibuf(ima, ibuf, nullptr);
3335 }
3337 }
3338
3340
3341 DEG_id_tag_update(&ima->id, 0);
3343
3344 return OPERATOR_FINISHED;
3345}
3346
3348{
3349 /* identifiers */
3350 ot->name = "Resize Image";
3351 ot->idname = "IMAGE_OT_resize";
3352 ot->description = "Resize the image";
3353
3354 /* API callbacks. */
3355 ot->invoke = image_scale_invoke;
3356 ot->exec = image_scale_exec;
3358
3359 /* properties */
3360 RNA_def_int_vector(ot->srna, "size", 2, nullptr, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
3362 ot->srna, "all_udims", false, "All UDIM Tiles", "Scale all the image's UDIM tiles");
3363
3364 /* flags */
3365 ot->flag = OPTYPE_REGISTER;
3366}
3367
3369
3370/* -------------------------------------------------------------------- */
3373
3374static bool image_pack_test(Image *ima, const char **r_error_message)
3375{
3376 if (!ima) {
3377 return false;
3378 }
3379
3380 if (!ID_IS_EDITABLE(&ima->id)) {
3381 *r_error_message = "Image is not editable";
3382 return false;
3383 }
3384
3386 *r_error_message = "Movies or image sequences do not support packing";
3387 return false;
3388 }
3389
3390 return true;
3391}
3392
3394{
3395 Image *ima = image_from_context(C);
3396 const char *error_message = nullptr;
3397
3398 if (image_pack_test(ima, &error_message)) {
3399 return true;
3400 }
3401
3402 if (error_message) {
3403 CTX_wm_operator_poll_msg_set(C, error_message);
3404 }
3405 return false;
3406}
3407
3409{
3410 Main *bmain = CTX_data_main(C);
3411 Image *ima = image_from_context(C);
3412
3413 const char *error_message = nullptr;
3414 if (!image_pack_test(ima, &error_message)) {
3415 if (error_message) {
3416 BKE_report(op->reports, RPT_ERROR, error_message);
3417 }
3418 return OPERATOR_CANCELLED;
3419 }
3420
3421 if (BKE_image_is_dirty(ima)) {
3423 }
3424 else {
3425 BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
3426 }
3427
3429
3430 return OPERATOR_FINISHED;
3431}
3432
3434{
3435 /* identifiers */
3436 ot->name = "Pack Image";
3437 ot->description = "Pack an image as embedded data into the .blend file";
3438 ot->idname = "IMAGE_OT_pack";
3439
3440 /* API callbacks. */
3441 ot->exec = image_pack_exec;
3442 ot->poll = image_pack_poll;
3443
3444 /* flags */
3445 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3446}
3447
3449
3450/* -------------------------------------------------------------------- */
3453
3455{
3456 Main *bmain = CTX_data_main(C);
3457 Image *ima = image_from_context(C);
3458 int method = RNA_enum_get(op->ptr, "method");
3459
3460 /* find the supplied image by name */
3461 if (RNA_struct_property_is_set(op->ptr, "id")) {
3462 char imaname[MAX_ID_NAME - 2];
3463 RNA_string_get(op->ptr, "id", imaname);
3464 ima = static_cast<Image *>(BLI_findstring(&bmain->images, imaname, offsetof(ID, name) + 2));
3465 if (!ima) {
3466 ima = image_from_context(C);
3467 }
3468 }
3469
3470 if (!ima || !BKE_image_has_packedfile(ima)) {
3471 return OPERATOR_CANCELLED;
3472 }
3473
3474 if (!ID_IS_EDITABLE(&ima->id)) {
3475 BKE_report(op->reports, RPT_ERROR, "Image is not editable");
3476 return OPERATOR_CANCELLED;
3477 }
3478
3480 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
3481 return OPERATOR_CANCELLED;
3482 }
3483
3484 if (G.fileflags & G_FILE_AUTOPACK) {
3485 BKE_report(op->reports,
3487 "AutoPack is enabled, so image will be packed again on file save");
3488 }
3489
3490 /* XXX BKE_packedfile_unpack_image frees image buffers */
3492
3494
3496
3497 return OPERATOR_FINISHED;
3498}
3499
3501{
3502 Image *ima = image_from_context(C);
3503
3504 if (RNA_struct_property_is_set(op->ptr, "id")) {
3505 return image_unpack_exec(C, op);
3506 }
3507
3508 if (!ima || !BKE_image_has_packedfile(ima)) {
3509 return OPERATOR_CANCELLED;
3510 }
3511
3512 if (!ID_IS_EDITABLE(&ima->id)) {
3513 BKE_report(op->reports, RPT_ERROR, "Image is not editable");
3514 return OPERATOR_CANCELLED;
3515 }
3516
3518 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
3519 return OPERATOR_CANCELLED;
3520 }
3521
3522 if (G.fileflags & G_FILE_AUTOPACK) {
3523 BKE_report(op->reports,
3525 "AutoPack is enabled, so image will be packed again on file save");
3526 }
3527
3528 unpack_menu(C,
3529 "IMAGE_OT_unpack",
3530 ima->id.name + 2,
3531 ima->filepath,
3532 "textures",
3534 ((ImagePackedFile *)ima->packedfiles.first)->packedfile :
3535 nullptr);
3536
3537 return OPERATOR_FINISHED;
3538}
3539
3541{
3542 /* identifiers */
3543 ot->name = "Unpack Image";
3544 ot->description = "Save an image packed in the .blend file to disk";
3545 ot->idname = "IMAGE_OT_unpack";
3546
3547 /* API callbacks. */
3548 ot->exec = image_unpack_exec;
3549 ot->invoke = image_unpack_invoke;
3550 ot->poll = image_pack_poll;
3551
3552 /* flags */
3553 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3554
3555 /* properties */
3557 ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
3558 /* XXX, weak!, will fail with library, name collisions */
3560 ot->srna, "id", nullptr, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
3561}
3562
3564
3565/* -------------------------------------------------------------------- */
3568
3570 ARegion *region,
3571 const int mval[2],
3572 float r_fpos[2])
3573{
3574 void *lock;
3575 ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
3576
3577 if (ibuf == nullptr) {
3579 return false;
3580 }
3581
3582 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &r_fpos[0], &r_fpos[1]);
3583
3585 return true;
3586}
3587
3589 SpaceImage *sima, ARegion *region, const int mval[2], float r_col[3], bool *r_is_data)
3590{
3591 if (r_is_data) {
3592 *r_is_data = false;
3593 }
3594 if (sima->image == nullptr) {
3595 return false;
3596 }
3597 float uv[2];
3598 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &uv[0], &uv[1]);
3599 int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, nullptr);
3600
3601 void *lock;
3603 bool ret = false;
3604
3605 if (ibuf == nullptr) {
3607 return false;
3608 }
3609
3610 if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
3611 const float *fp;
3612 uchar *cp;
3613 int x = int(uv[0] * ibuf->x), y = int(uv[1] * ibuf->y);
3614
3615 CLAMP(x, 0, ibuf->x - 1);
3616 CLAMP(y, 0, ibuf->y - 1);
3617
3618 if (ibuf->float_buffer.data) {
3619 fp = (ibuf->float_buffer.data + (ibuf->channels) * (y * ibuf->x + x));
3620 copy_v3_v3(r_col, fp);
3621 ret = true;
3622 }
3623 else if (ibuf->byte_buffer.data) {
3624 cp = ibuf->byte_buffer.data + 4 * (y * ibuf->x + x);
3625 rgb_uchar_to_float(r_col, cp);
3627 ret = true;
3628 }
3629 }
3630
3631 if (r_is_data) {
3632 *r_is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
3633 }
3634
3636 return ret;
3637}
3638
3640{
3641 /* identifiers */
3642 ot->name = "Sample Color";
3643 ot->idname = "IMAGE_OT_sample";
3644 ot->description = "Use mouse to sample a color in current image";
3645
3646 /* API callbacks. */
3647 ot->invoke = ED_imbuf_sample_invoke;
3648 ot->modal = ED_imbuf_sample_modal;
3649 ot->cancel = ED_imbuf_sample_cancel;
3650 ot->poll = ED_imbuf_sample_poll;
3651
3652 /* flags */
3653 ot->flag = OPTYPE_BLOCKING;
3654
3655 PropertyRNA *prop;
3656 prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3659}
3660
3662
3663/* -------------------------------------------------------------------- */
3666
3668{
3670 ARegion *region = CTX_wm_region(C);
3671 Scene *scene = CTX_data_scene(C);
3672 Image *ima = ED_space_image(sima);
3673
3674 int x_start = RNA_int_get(op->ptr, "xstart");
3675 int y_start = RNA_int_get(op->ptr, "ystart");
3676 int x_end = RNA_int_get(op->ptr, "xend");
3677 int y_end = RNA_int_get(op->ptr, "yend");
3678
3679 float uv1[2], uv2[2], ofs[2];
3680 UI_view2d_region_to_view(&region->v2d, x_start, y_start, &uv1[0], &uv1[1]);
3681 UI_view2d_region_to_view(&region->v2d, x_end, y_end, &uv2[0], &uv2[1]);
3682
3683 /* If the image has tiles, shift the positions accordingly. */
3684 int tile = BKE_image_get_tile_from_pos(ima, uv1, uv1, ofs);
3685 sub_v2_v2(uv2, ofs);
3686
3687 void *lock;
3689 Histogram *hist = &sima->sample_line_hist;
3690
3691 if (ibuf == nullptr) {
3693 return OPERATOR_CANCELLED;
3694 }
3695 /* hmmmm */
3696 if (ibuf->channels < 3) {
3698 return OPERATOR_CANCELLED;
3699 }
3700
3701 copy_v2_v2(hist->co[0], uv1);
3702 copy_v2_v2(hist->co[1], uv2);
3703
3704 /* enable line drawing */
3705 hist->flag |= HISTO_FLAG_SAMPLELINE;
3706
3708
3709 /* reset y zoom */
3710 hist->ymax = 1.0f;
3711
3713
3715
3716 return OPERATOR_FINISHED;
3717}
3718
3720{
3722
3723 Histogram *hist = &sima->sample_line_hist;
3725
3726 if (!ED_space_image_has_buffer(sima)) {
3727 return OPERATOR_CANCELLED;
3728 }
3729
3730 return WM_gesture_straightline_invoke(C, op, event);
3731}
3732
3734{
3735 /* identifiers */
3736 ot->name = "Sample Line";
3737 ot->idname = "IMAGE_OT_sample_line";
3738 ot->description = "Sample a line and show it in Scope panels";
3739
3740 /* API callbacks. */
3741 ot->invoke = image_sample_line_invoke;
3743 ot->exec = image_sample_line_exec;
3746
3747 /* flags */
3748 ot->flag = 0; /* no undo/register since this operates on the space */
3749
3751}
3752
3754
3755/* -------------------------------------------------------------------- */
3758
3760{
3761 static const EnumPropertyItem point_items[] = {
3762 {0, "BLACK_POINT", 0, "Black Point", ""},
3763 {1, "WHITE_POINT", 0, "White Point", ""},
3764 {0, nullptr, 0, nullptr, nullptr},
3765 };
3766
3767 /* identifiers */
3768 ot->name = "Set Curves Point";
3769 ot->idname = "IMAGE_OT_curves_point_set";
3770 ot->description = "Set black point or white point for curves";
3771
3772 /* flags */
3773 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3774
3775 /* API callbacks. */
3776 ot->invoke = ED_imbuf_sample_invoke;
3777 ot->modal = ED_imbuf_sample_modal;
3778 ot->cancel = ED_imbuf_sample_cancel;
3780
3781 /* properties */
3783 ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
3784
3785 PropertyRNA *prop;
3786 prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
3789}
3790
3792
3793/* -------------------------------------------------------------------- */
3796
3798{
3799 Image *ima = image_from_context(C);
3800
3801 return (ima && ima->type == IMA_TYPE_R_RESULT);
3802}
3803
3805{
3806 Image *ima = image_from_context(C);
3807 const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
3808
3809 if (!ED_image_slot_cycle(ima, direction)) {
3810 return OPERATOR_CANCELLED;
3811 }
3812
3814
3815 /* no undo push for browsing existing */
3817 if ((slot && slot->render) || ima->render_slot == ima->last_render_slot) {
3818 return OPERATOR_CANCELLED;
3819 }
3820
3821 return OPERATOR_FINISHED;
3822}
3823
3825{
3826 /* identifiers */
3827 ot->name = "Cycle Render Slot";
3828 ot->idname = "IMAGE_OT_cycle_render_slot";
3829 ot->description = "Cycle through all non-void render slots";
3830
3831 /* API callbacks. */
3834
3835 /* flags */
3836 ot->flag = OPTYPE_REGISTER;
3837
3838 RNA_def_boolean(ot->srna, "reverse", false, "Cycle in Reverse", "");
3839}
3840
3842
3843/* -------------------------------------------------------------------- */
3846
3848{
3849 Image *ima = image_from_context(C);
3851
3852 if (!BKE_image_clear_renderslot(ima, iuser, ima->render_slot)) {
3853 return OPERATOR_CANCELLED;
3854 }
3855
3857
3858 return OPERATOR_FINISHED;
3859}
3860
3862{
3863 /* identifiers */
3864 ot->name = "Clear Render Slot";
3865 ot->idname = "IMAGE_OT_clear_render_slot";
3866 ot->description = "Clear the currently selected render slot";
3867
3868 /* API callbacks. */
3871
3872 /* flags */
3873 ot->flag = OPTYPE_REGISTER;
3874}
3875
3877
3878/* -------------------------------------------------------------------- */
3881
3883{
3884 Image *ima = image_from_context(C);
3885
3886 RenderSlot *slot = BKE_image_add_renderslot(ima, nullptr);
3887 ima->render_slot = BLI_findindex(&ima->renderslots, slot);
3888
3890
3891 return OPERATOR_FINISHED;
3892}
3893
3895{
3896 /* identifiers */
3897 ot->name = "Add Render Slot";
3898 ot->idname = "IMAGE_OT_add_render_slot";
3899 ot->description = "Add a new render slot";
3900
3901 /* API callbacks. */
3904
3905 /* flags */
3906 ot->flag = OPTYPE_REGISTER;
3907}
3908
3910
3911/* -------------------------------------------------------------------- */
3914
3916{
3917 Image *ima = image_from_context(C);
3919
3920 if (!BKE_image_remove_renderslot(ima, iuser, ima->render_slot)) {
3921 return OPERATOR_CANCELLED;
3922 }
3923
3925
3926 return OPERATOR_FINISHED;
3927}
3928
3930{
3931 /* identifiers */
3932 ot->name = "Remove Render Slot";
3933 ot->idname = "IMAGE_OT_remove_render_slot";
3934 ot->description = "Remove the current render slot";
3935
3936 /* API callbacks. */
3939
3940 /* flags */
3941 ot->flag = OPTYPE_REGISTER;
3942}
3943
3945
3946/* -------------------------------------------------------------------- */
3949
3951{
3952 /* prevent changes during render */
3953 if (G.is_rendering) {
3954 return false;
3955 }
3956
3958}
3959
3961{
3962 Scene *scene = CTX_data_scene(C);
3963
3964 /* set the new frame number */
3965 scene->r.cfra = RNA_int_get(op->ptr, "frame");
3967 scene->r.subframe = 0.0f;
3968
3969 /* do updates */
3972}
3973
3975{
3976 change_frame_apply(C, op);
3977
3978 return OPERATOR_FINISHED;
3979}
3980
3981static int frame_from_event(bContext *C, const wmEvent *event)
3982{
3983 ARegion *region = CTX_wm_region(C);
3984 Scene *scene = CTX_data_scene(C);
3985 int framenr = 0;
3986
3987 if (region->regiontype == RGN_TYPE_WINDOW) {
3988 float sfra = scene->r.sfra, efra = scene->r.efra, framelen = region->winx / (efra - sfra + 1);
3989
3990 framenr = sfra + event->mval[0] / framelen;
3991 }
3992 else {
3993 float viewx, viewy;
3994
3995 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
3996
3997 framenr = round_fl_to_int(viewx);
3998 }
3999
4000 return framenr;
4001}
4002
4004{
4005 ARegion *region = CTX_wm_region(C);
4006
4007 if (region->regiontype == RGN_TYPE_WINDOW) {
4008 const SpaceImage *sima = CTX_wm_space_image(C);
4009 if (!ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
4010 return OPERATOR_PASS_THROUGH;
4011 }
4012 }
4013
4014 RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
4015
4016 change_frame_apply(C, op);
4017
4018 /* add temp handler */
4020
4022}
4023
4025{
4026 switch (event->type) {
4027 case EVT_ESCKEY:
4028 return OPERATOR_FINISHED;
4029
4030 case MOUSEMOVE:
4031 RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
4032 change_frame_apply(C, op);
4033 break;
4034
4035 case LEFTMOUSE:
4036 case RIGHTMOUSE:
4037 if (event->val == KM_RELEASE) {
4038 return OPERATOR_FINISHED;
4039 }
4040 break;
4041 default: {
4042 break;
4043 }
4044 }
4045
4047}
4048
4050{
4051 /* identifiers */
4052 ot->name = "Change Frame";
4053 ot->idname = "IMAGE_OT_change_frame";
4054 ot->description = "Interactively change the current frame number";
4055
4056 /* API callbacks. */
4057 ot->exec = change_frame_exec;
4058 ot->invoke = change_frame_invoke;
4059 ot->modal = change_frame_modal;
4060 ot->poll = change_frame_poll;
4061
4062 /* flags */
4063 ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
4064
4065 /* rna */
4066 RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
4067}
4068
4069/* Reload cached render results... */
4070/* goes over all scenes, reads render layers */
4072{
4073 Main *bmain = CTX_data_main(C);
4074 Scene *scene = CTX_data_scene(C);
4076 Image *ima;
4077
4078 ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
4079 if (sima->image == nullptr) {
4080 ED_space_image_set(bmain, sima, ima, false);
4081 }
4082
4083 RE_ReadRenderResult(scene, scene);
4084
4086 return OPERATOR_FINISHED;
4087}
4088
4090{
4091 ot->name = "Open Cached Render";
4092 ot->idname = "IMAGE_OT_read_viewlayers";
4093 ot->description = "Read all the current scene's view layers from cache, as needed";
4094
4097
4098 /* flags */
4099 ot->flag = 0;
4100}
4101
4103
4104/* -------------------------------------------------------------------- */
4107
4109{
4110 ARegion *region = CTX_wm_region(C);
4111 Scene *scene = CTX_data_scene(C);
4112 Render *re = RE_GetSceneRender(scene);
4114
4115 if (re == nullptr) {
4116 /* Shouldn't happen, but better be safe close to the release. */
4117 return OPERATOR_CANCELLED;
4118 }
4119
4120 /* Get information about the previous render, or current scene if no render yet. */
4121 int width, height;
4122 BKE_render_resolution(&scene->r, false, &width, &height);
4124 &scene->r;
4125
4126 /* Get rectangle from the operator. */
4127 rctf border;
4129 UI_view2d_region_to_view_rctf(&region->v2d, &border, &border);
4130
4131 /* Adjust for cropping. */
4132 if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
4133 border.xmin = rd->border.xmin + border.xmin * (rd->border.xmax - rd->border.xmin);
4134 border.xmax = rd->border.xmin + border.xmax * (rd->border.xmax - rd->border.xmin);
4135 border.ymin = rd->border.ymin + border.ymin * (rd->border.ymax - rd->border.ymin);
4136 border.ymax = rd->border.ymin + border.ymax * (rd->border.ymax - rd->border.ymin);
4137 }
4138
4139 CLAMP(border.xmin, 0.0f, 1.0f);
4140 CLAMP(border.ymin, 0.0f, 1.0f);
4141 CLAMP(border.xmax, 0.0f, 1.0f);
4142 CLAMP(border.ymax, 0.0f, 1.0f);
4143
4144 /* Drawing a border surrounding the entire camera view switches off border rendering
4145 * or the border covers no pixels. */
4146 if ((border.xmin <= 0.0f && border.xmax >= 1.0f && border.ymin <= 0.0f && border.ymax >= 1.0f) ||
4147 (border.xmin == border.xmax || border.ymin == border.ymax))
4148 {
4149 scene->r.mode &= ~R_BORDER;
4150 }
4151 else {
4152 /* Snap border to pixel boundaries, so drawing a border within a pixel selects that pixel. */
4153 border.xmin = floorf(border.xmin * width) / width;
4154 border.xmax = ceilf(border.xmax * width) / width;
4155 border.ymin = floorf(border.ymin * height) / height;
4156 border.ymax = ceilf(border.ymax * height) / height;
4157
4158 /* Set border. */
4159 scene->r.border = border;
4160 scene->r.mode |= R_BORDER;
4161 }
4162
4165
4166 return OPERATOR_FINISHED;
4167}
4168
4170{
4171 /* identifiers */
4172 ot->name = "Render Region";
4173 ot->description = "Set the boundaries of the render region and enable render region";
4174 ot->idname = "IMAGE_OT_render_border";
4175
4176 /* API callbacks. */
4177 ot->invoke = WM_gesture_box_invoke;
4178 ot->exec = render_border_exec;
4179 ot->modal = WM_gesture_box_modal;
4180 ot->cancel = WM_gesture_box_cancel;
4182
4183 /* flags */
4184 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4185
4186 /* rna */
4188}
4189
4191
4192/* -------------------------------------------------------------------- */
4195
4197{
4198 Scene *scene = CTX_data_scene(C);
4199 scene->r.mode &= ~R_BORDER;
4201 BLI_rctf_init(&scene->r.border, 0.0f, 1.0f, 0.0f, 1.0f);
4202 return OPERATOR_FINISHED;
4203}
4204
4206{
4207 /* identifiers */
4208 ot->name = "Clear Render Region";
4209 ot->description = "Clear the boundaries of the render region and disable render region";
4210 ot->idname = "IMAGE_OT_clear_render_border";
4211
4212 /* API callbacks. */
4215
4216 /* flags */
4217 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4218}
4219
4221
4222/* -------------------------------------------------------------------- */
4225
4227{
4228 RNA_float_get_array(ptr, "color", tile->gen_color);
4229 tile->gen_type = RNA_enum_get(ptr, "generated_type");
4230 tile->gen_x = RNA_int_get(ptr, "width");
4231 tile->gen_y = RNA_int_get(ptr, "height");
4232 bool is_float = RNA_boolean_get(ptr, "float");
4233
4234 tile->gen_flag = is_float ? IMA_GEN_FLOAT : 0;
4235 tile->gen_depth = RNA_boolean_get(ptr, "alpha") ? 32 : 24;
4236
4237 return BKE_image_fill_tile(ima, tile);
4238}
4239
4241{
4242 layout->use_property_split_set(true);
4243 layout->use_property_decorate_set(false);
4244
4245 uiLayout *col = &layout->column(false);
4246 col->prop(ptr, "color", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4247 col->prop(ptr, "width", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4248 col->prop(ptr, "height", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4249 col->prop(ptr, "alpha", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4250 col->prop(ptr, "generated_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4251 col->prop(ptr, "float", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4252}
4253
4255{
4256 ImageUser iuser;
4257 BKE_imageuser_default(&iuser);
4258 if (tile != nullptr) {
4259 iuser.tile = tile->tile_number;
4260 }
4261
4262 /* Acquire ibuf to get the default values.
4263 * If the specified tile has no ibuf, try acquiring the main tile instead
4264 * (unless the specified tile already was the first tile). */
4265 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
4266 if (ibuf == nullptr && (tile != nullptr) && (tile != ima->tiles.first)) {
4267 ibuf = BKE_image_acquire_ibuf(ima, nullptr, nullptr);
4268 }
4269
4270 if (ibuf != nullptr) {
4271 /* Initialize properties from reference tile. */
4272 RNA_int_set(ptr, "width", ibuf->x);
4273 RNA_int_set(ptr, "height", ibuf->y);
4274 RNA_boolean_set(ptr, "float", ibuf->float_buffer.data != nullptr);
4275 RNA_boolean_set(ptr, "alpha", ibuf->planes > 24);
4276
4277 BKE_image_release_ibuf(ima, ibuf, nullptr);
4278 }
4279}
4280
4282{
4283 PropertyRNA *prop;
4284 static const float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
4285 prop = RNA_def_float_color(
4286 srna, "color", 4, nullptr, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
4288 RNA_def_property_float_array_default(prop, default_color);
4289 RNA_def_enum(srna,
4290 "generated_type",
4293 "Generated Type",
4294 "Fill the image with a grid for UV map testing");
4295 prop = RNA_def_int(srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
4297 prop = RNA_def_int(srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
4299
4300 /* Only needed when filling the first tile. */
4302 srna, "float", false, "32-bit Float", "Create image with 32-bit floating-point bit depth");
4303 RNA_def_boolean(srna, "alpha", true, "Alpha", "Create an image with an alpha channel");
4304}
4305
4307{
4308 Image *ima = CTX_data_edit_image(C);
4309
4310 return (ima != nullptr && ima->source == IMA_SRC_TILED && BKE_image_has_ibuf(ima, nullptr));
4311}
4312
4314{
4315 Image *ima = CTX_data_edit_image(C);
4316
4317 int start_tile = RNA_int_get(op->ptr, "number");
4318 int end_tile = start_tile + RNA_int_get(op->ptr, "count") - 1;
4319
4320 if (start_tile < 1001 || end_tile > IMA_UDIM_MAX) {
4321 BKE_report(op->reports, RPT_ERROR, "Invalid UDIM index range was specified");
4322 return OPERATOR_CANCELLED;
4323 }
4324
4325 bool fill_tile = RNA_boolean_get(op->ptr, "fill");
4326 std::string label = RNA_string_get(op->ptr, "label");
4327
4328 /* BKE_image_add_tile assumes a pre-sorted list of tiles. */
4330
4331 ImageTile *last_tile_created = nullptr;
4332 for (int tile_number = start_tile; tile_number <= end_tile; tile_number++) {
4333 ImageTile *tile = BKE_image_add_tile(ima, tile_number, label.c_str());
4334
4335 if (tile != nullptr) {
4336 if (fill_tile) {
4337 do_fill_tile(op->ptr, ima, tile);
4338 }
4339
4340 last_tile_created = tile;
4341 }
4342 }
4343
4344 if (!last_tile_created) {
4345 BKE_report(op->reports, RPT_WARNING, "No UDIM tiles were created");
4346 return OPERATOR_CANCELLED;
4347 }
4348
4349 ima->active_tile_index = BLI_findindex(&ima->tiles, last_tile_created);
4350
4352 return OPERATOR_FINISHED;
4353}
4354
4356{
4357 Image *ima = CTX_data_edit_image(C);
4358
4359 /* Find the first gap in tile numbers or the number after the last if
4360 * no gap exists. */
4361 int next_number = 0;
4362 LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
4363 next_number = tile->tile_number + 1;
4364 if (tile->next == nullptr || tile->next->tile_number > next_number) {
4365 break;
4366 }
4367 }
4368
4369 ImageTile *tile = static_cast<ImageTile *>(BLI_findlink(&ima->tiles, ima->active_tile_index));
4370 tile_fill_init(op->ptr, ima, tile);
4371
4372 RNA_int_set(op->ptr, "number", next_number);
4373 RNA_int_set(op->ptr, "count", 1);
4374 RNA_string_set(op->ptr, "label", "");
4375
4377 op,
4378 300,
4379 IFACE_("Add Tile to Image"),
4381}
4382
4383static void tile_add_draw(bContext * /*C*/, wmOperator *op)
4384{
4385 uiLayout *col;
4386 uiLayout *layout = op->layout;
4387
4388 layout->use_property_split_set(true);
4389 layout->use_property_decorate_set(false);
4390
4391 col = &layout->column(false);
4392 col->prop(op->ptr, "number", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4393 col->prop(op->ptr, "count", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4394 col->prop(op->ptr, "label", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4395 layout->prop(op->ptr, "fill", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4396
4397 if (RNA_boolean_get(op->ptr, "fill")) {
4398 draw_fill_tile(op->ptr, layout);
4399 }
4400}
4401
4403{
4404 PropertyRNA *prop;
4405
4406 /* identifiers */
4407 ot->name = "Add Tile";
4408 ot->description = "Adds a tile to the image";
4409 ot->idname = "IMAGE_OT_tile_add";
4410
4411 /* API callbacks. */
4412 ot->poll = tile_add_poll;
4413 ot->exec = tile_add_exec;
4414 ot->invoke = tile_add_invoke;
4415 ot->ui = tile_add_draw;
4416
4417 /* flags */
4418 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4419
4420 RNA_def_int(ot->srna,
4421 "number",
4422 1002,
4423 1001,
4425 "Number",
4426 "UDIM number of the tile",
4427 1001,
4428 1099);
4429 RNA_def_int(ot->srna, "count", 1, 1, INT_MAX, "Count", "How many tiles to add", 1, 1000);
4430 RNA_def_string(ot->srna, "label", nullptr, 0, "Label", "Optional tile label");
4431 prop = RNA_def_boolean(ot->srna, "fill", true, "Fill", "Fill new tile with a generated image");
4433 def_fill_tile(ot->srna);
4434}
4435
4437
4438/* -------------------------------------------------------------------- */
4441
4443{
4444 Image *ima = CTX_data_edit_image(C);
4445
4446 return (ima != nullptr && ima->source == IMA_SRC_TILED && !BLI_listbase_is_single(&ima->tiles));
4447}
4448
4450{
4451 Image *ima = CTX_data_edit_image(C);
4452
4453 ImageTile *tile = static_cast<ImageTile *>(BLI_findlink(&ima->tiles, ima->active_tile_index));
4454 if (!BKE_image_remove_tile(ima, tile)) {
4455 return OPERATOR_CANCELLED;
4456 }
4457
4458 /* Ensure that the active index is valid. */
4460
4462
4463 return OPERATOR_FINISHED;
4464}
4465
4467{
4468 /* identifiers */
4469 ot->name = "Remove Tile";
4470 ot->description = "Removes a tile from the image";
4471 ot->idname = "IMAGE_OT_tile_remove";
4472
4473 /* API callbacks. */
4474 ot->poll = tile_remove_poll;
4475 ot->exec = tile_remove_exec;
4476
4477 /* flags */
4478 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4479}
4480
4482
4483/* -------------------------------------------------------------------- */
4486
4488{
4489 Image *ima = CTX_data_edit_image(C);
4490
4491 if (ima != nullptr && ima->source == IMA_SRC_TILED) {
4492 /* Filling secondary tiles is only allowed if the primary tile exists. */
4493 return (ima->active_tile_index == 0) || BKE_image_has_ibuf(ima, nullptr);
4494 }
4495 return false;
4496}
4497
4499{
4500 Image *ima = CTX_data_edit_image(C);
4501
4502 ImageTile *tile = static_cast<ImageTile *>(BLI_findlink(&ima->tiles, ima->active_tile_index));
4503 if (!do_fill_tile(op->ptr, ima, tile)) {
4504 return OPERATOR_CANCELLED;
4505 }
4506
4508
4509 return OPERATOR_FINISHED;
4510}
4511
4513{
4514 tile_fill_init(op->ptr, CTX_data_edit_image(C), nullptr);
4515
4517 op,
4518 300,
4519 IFACE_("Fill Tile With Generated Image"),
4521}
4522
4523static void tile_fill_draw(bContext * /*C*/, wmOperator *op)
4524{
4525 draw_fill_tile(op->ptr, op->layout);
4526}
4527
4529{
4530 /* identifiers */
4531 ot->name = "Fill Tile";
4532 ot->description = "Fill the current tile with a generated image";
4533 ot->idname = "IMAGE_OT_tile_fill";
4534
4535 /* API callbacks. */
4536 ot->poll = tile_fill_poll;
4537 ot->exec = tile_fill_exec;
4538 ot->invoke = tile_fill_invoke;
4539 ot->ui = tile_fill_draw;
4540
4541 /* flags */
4542 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4543
4544 def_fill_tile(ot->srna);
4545}
4546
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:48
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:171
bool BKE_image_is_multiview(const Image *ima)
#define IMA_SIGNAL_USER_NEW_IMAGE
Definition BKE_image.hh:173
void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy)
#define IMA_SIGNAL_RELOAD
Definition BKE_image.hh:168
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_set(ImageFormatData *imf, ID *owner_id, const char imtype)
void BKE_image_format_init_for_write(ImageFormatData *imf, const Scene *scene_src, const ImageFormatData *imf_src, const bool allow_video=false)
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:51
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:879
void id_us_min(ID *id)
Definition lib_id.cc:366
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
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
@ RPT_STORE
Definition BKE_report.hh:56
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_reports_free(ReportList *reports)
Definition report.cc:97
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:82
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2915
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:360
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)
MINLINE 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:661
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
unsigned char uchar
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:113
#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:1125
@ ID_RECALC_SOURCE
Definition DNA_ID.h:1143
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_EDITORS
Definition DNA_ID.h:1111
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
#define MAX_ID_NAME
Definition DNA_ID.h:373
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:685
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ 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_GENTYPE_BLANK
@ IMA_USE_VIEWS
@ IMA_VIEW_AS_RENDER
@ IMA_TYPE_MULTILAYER
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
Object is a sort of wrapper for general info.
#define MINAFRAME
@ R_CROP
@ R_BORDER
@ R_IMF_CHAN_DEPTH_8
@ R_IMF_IMTYPE_PNG
@ 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)
ListBase ED_image_filesel_detect_sequences(blender::StringRefNull blendfile_path, blender::StringRefNull root_path, wmOperator *op, bool detect_udim)
void ED_space_image_set(Main *bmain, SpaceImage *sima, Image *ima, bool automatic)
Definition image_edit.cc:46
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:693
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
bool ED_operator_uvedit(bContext *C)
void ED_undo_push_op(bContext *C, wmOperator *op)
Definition ed_undo.cc:359
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:368
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:23
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:465
@ IB_BITMAPDIRTY
@ IB_DISPLAY_BUFFER_INVALID
const char * imb_ext_movie[]
@ IMB_COLORMANAGE_IS_DATA
@ IB_byte_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:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
@ PROP_PIXEL
Definition RNA_types.hh:248
@ PROP_COLOR_GAMMA
Definition RNA_types.hh:272
#define C
Definition RandGen.cpp:29
void uiTemplateImageSettings(uiLayout *layout, bContext *C, PointerRNA *imfptr, bool color_management, const char *panel_idname=nullptr)
@ 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)
#define UI_ITEM_NONE
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:1668
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1675
@ WM_FILESEL_FILES
Definition WM_api.hh:1125
@ WM_FILESEL_DIRECTORY
Definition WM_api.hh:1122
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1121
@ WM_FILESEL_SHOW_PROPS
Definition WM_api.hh:1127
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1124
@ FILE_OPENFILE
Definition WM_api.hh:1133
@ FILE_SAVE
Definition WM_api.hh:1134
@ KM_ALT
Definition WM_types.hh:280
@ KM_SHIFT
Definition WM_types.hh:278
#define ND_DRAW
Definition WM_types.hh:461
#define ND_RENDER_OPTIONS
Definition WM_types.hh:435
@ KM_RELEASE
Definition WM_types.hh:312
#define NC_SCENE
Definition WM_types.hh:378
#define NA_ADDED
Definition WM_types.hh:586
@ 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 ND_SPACE_IMAGE
Definition WM_types.hh:522
#define NA_EDITED
Definition WM_types.hh:584
#define NC_IMAGE
Definition WM_types.hh:384
#define ND_FRAME
Definition WM_types.hh:434
#define NC_SPACE
Definition WM_types.hh:392
static wmOperatorStatus change_frame_exec(bContext *C, wmOperator *op)
Definition anim_ops.cc:590
static wmOperatorStatus change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition anim_ops.cc:750
static wmOperatorStatus change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition anim_ops.cc:677
static float frame_from_event(bContext *C, const wmEvent *event)
Definition anim_ops.cc:600
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
nullptr float
#define powf(x, y)
#define roundf(x)
#define offsetof(t, d)
#define GS(x)
uint col
#define active
constexpr T degrees(T) RET
bool space_image_main_region_poll(bContext *C)
Definition image_ops.cc:332
static wmOperatorStatus image_match_len_exec(bContext *C, wmOperator *)
void IMAGE_OT_view_cursor_center(wmOperatorType *ot)
Definition image_ops.cc:900
static wmOperatorStatus image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:444
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)
@ GEN_CONTEXT_NONE
@ GEN_CONTEXT_PAINT_CANVAS
@ GEN_CONTEXT_PAINT_STENCIL
void IMAGE_OT_view_zoom(wmOperatorType *ot)
Definition image_ops.cc:736
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:139
static void image_new_cancel(bContext *, wmOperator *op)
static void image_view_pan_exit(bContext *C, wmOperator *op, bool cancel)
Definition image_ops.cc:395
bool ED_image_should_save_modified(const Main *bmain)
static wmOperatorStatus image_remove_render_slot_exec(bContext *C, wmOperator *)
static void image_view_zoom_cancel(bContext *C, wmOperator *op)
Definition image_ops.cc:731
static void def_fill_tile(StructOrFunctionRNA *srna)
static Image * image_from_context(const bContext *C)
Definition image_ops.cc:176
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:228
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:426
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:268
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:854
static wmOperatorStatus image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition image_ops.cc:684
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:475
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:531
static bool image_not_packed_poll(bContext *C)
Definition image_ops.cc:261
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_save_as_draw(bContext *C, 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:372
static wmOperatorStatus image_view_all_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:838
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:566
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:881
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:604
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:332
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:586
void IMAGE_OT_replace(wmOperatorType *ot)
static void sima_zoom_set_from_bounds(SpaceImage *sima, ARegion *region, const rctf *bounds)
Definition image_ops.cc:151
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:470
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:99
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:924
static wmOperatorStatus image_view_pan_exec(bContext *C, wmOperator *op)
Definition image_ops.cc:412
void IMAGE_OT_view_center_cursor(wmOperatorType *ot)
Definition image_ops.cc:936
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:207
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:191
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:344
static wmOperatorStatus image_clipboard_paste_exec(bContext *C, wmOperator *op)
static wmOperatorStatus image_view_selected_exec(bContext *C, wmOperator *)
Definition image_ops.cc:954
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:247
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:637
@ VIEW_CONFIRM
Definition image_ops.cc:601
@ VIEW_PASS
Definition image_ops.cc:599
@ VIEW_APPLY
Definition image_ops.cc:600
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
const char * name
return ret
#define floorf
#define ceilf
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)
int RNA_int_get(PointerRNA *ptr, const char *name)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
float RNA_float_get(PointerRNA *ptr, const char *name)
std::string RNA_string_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:414
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
const ColorSpace * colorspace
char filepath[IMB_FILEPATH_SIZE]
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
int colormanage_flag
unsigned char planes
Stereo3dFormat stereo3d_format
char filepath[FILE_MAX]
Definition ED_image.hh:200
ListBase udim_tiles
Definition ED_image.hh:208
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:579
void * first
ListBase images
Definition BKE_main.hh:286
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
PropertyRNA * prop
Definition RNA_types.hh:146
struct RenderResult * render
ListBase list
Definition BKE_report.hh:75
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
void use_property_decorate_set(bool is_sep)
uiLayout & column(bool align)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
void use_property_split_set(bool value)
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:774
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int xy[2]
Definition WM_types.hh:761
int mval[2]
Definition WM_types.hh:763
void * customdata
Definition WM_types.hh:807
const char * name
Definition WM_types.hh:1033
struct ReportList * reports
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
wmWindow * win
Definition WM_types.hh:956
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)
bool WM_cursor_modal_is_set_ok(const wmWindow *win)
@ 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)
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
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)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorStatus WM_operator_name_call(bContext *C, const char *opstring, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
@ MOUSEPAN
@ RIGHTMOUSE
@ TIMER
@ MOUSEZOOM
@ MOUSEMOVE
@ LEFTMOUSE
@ NDOF_MOTION
@ EVT_ESCKEY
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
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, std::optional< std::string > message)
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)