4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * Contributor(s): Blender Foundation, 2002-2009
25 * ***** END GPL LICENSE BLOCK *****
31 #include "MEM_guardedalloc.h"
33 #include "DNA_image_types.h"
34 #include "DNA_node_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_packedFile_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_userdef_types.h"
41 #include "DNA_windowmanager_types.h"
43 #include "BKE_colortools.h"
44 #include "BKE_context.h"
45 #include "BKE_image.h"
46 #include "BKE_global.h"
47 #include "BKE_library.h"
49 #include "BKE_packedFile.h"
50 #include "BKE_report.h"
51 #include "BKE_screen.h"
53 #include "BLI_arithb.h"
54 #include "BLI_blenlib.h"
56 #include "IMB_imbuf.h"
57 #include "IMB_imbuf_types.h"
59 #include "RE_pipeline.h"
61 #include "RNA_access.h"
62 #include "RNA_define.h"
63 #include "RNA_types.h"
66 #include "ED_screen.h"
67 #include "ED_space_api.h"
68 #include "ED_uvedit.h"
70 #include "UI_interface.h"
71 #include "UI_resources.h"
72 #include "UI_view2d.h"
77 #include "image_intern.h"
79 /******************** view navigation utilities *********************/
81 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom)
83 float oldzoom= sima->zoom;
88 if (sima->zoom > 0.1f && sima->zoom < 4.0f)
91 /* check zoom limits */
92 ED_space_image_size(sima, &width, &height);
97 if((width < 4) && (height < 4))
99 else if((ar->winrct.xmax - ar->winrct.xmin) <= sima->zoom)
101 else if((ar->winrct.ymax - ar->winrct.ymin) <= sima->zoom)
105 static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac)
107 sima_zoom_set(sima, ar, sima->zoom*zoomfac);
110 static int space_image_poll(bContext *C)
112 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
113 if(sima && sima->spacetype==SPACE_IMAGE)
114 if(ED_space_image_buffer(sima))
119 static int space_image_file_exists_poll(bContext *C)
121 if(space_image_poll(C)) {
122 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
123 ImBuf *ibuf= ED_space_image_buffer(sima);
125 if(ibuf && BLI_exists(ibuf->name) && BLI_is_writable(ibuf->name))
132 int space_image_main_area_poll(bContext *C)
134 SpaceLink *slink= CTX_wm_space_data(C);
135 // XXX ARegion *ar= CTX_wm_region(C);
137 if(slink && (slink->spacetype == SPACE_IMAGE))
138 return 1; // XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW);
143 /********************** view pan operator *********************/
145 typedef struct ViewPanData {
150 static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event)
152 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
155 op->customdata= vpd= MEM_callocN(sizeof(ViewPanData), "ImageViewPanData");
156 WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
163 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
166 static void view_pan_exit(bContext *C, wmOperator *op, int cancel)
168 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
169 ViewPanData *vpd= op->customdata;
174 ED_area_tag_redraw(CTX_wm_area(C));
177 WM_cursor_restore(CTX_wm_window(C));
178 MEM_freeN(op->customdata);
181 static int view_pan_exec(bContext *C, wmOperator *op)
183 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
186 RNA_float_get_array(op->ptr, "offset", offset);
187 sima->xof += offset[0];
188 sima->yof += offset[1];
190 ED_area_tag_redraw(CTX_wm_area(C));
194 if(image_preview_active(curarea, NULL, NULL)) {
195 /* recalculates new preview rect */
196 scrarea_do_windraw(curarea);
197 image_preview_event(2);
201 return OPERATOR_FINISHED;
204 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
206 view_pan_init(C, op, event);
207 return OPERATOR_RUNNING_MODAL;
210 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
212 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
213 ViewPanData *vpd= op->customdata;
216 switch(event->type) {
220 offset[0]= (vpd->x - event->x)/sima->zoom;
221 offset[1]= (vpd->y - event->y)/sima->zoom;
222 RNA_float_set_array(op->ptr, "offset", offset);
223 view_pan_exec(C, op);
227 view_pan_exit(C, op, 0);
228 return OPERATOR_FINISHED;
233 return OPERATOR_RUNNING_MODAL;
236 static int view_pan_cancel(bContext *C, wmOperator *op)
238 view_pan_exit(C, op, 1);
239 return OPERATOR_CANCELLED;
242 void IMAGE_OT_view_pan(wmOperatorType *ot)
245 ot->name= "View Pan";
246 ot->idname= "IMAGE_OT_view_pan";
249 ot->exec= view_pan_exec;
250 ot->invoke= view_pan_invoke;
251 ot->modal= view_pan_modal;
252 ot->cancel= view_pan_cancel;
253 ot->poll= space_image_main_area_poll;
256 RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
257 "Offset", "Offset in floating point units, 1.0 is the width and height of the image.", -FLT_MAX, FLT_MAX);
260 /********************** view zoom operator *********************/
262 typedef struct ViewZoomData {
267 static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event)
269 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
272 op->customdata= vpd= MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData");
273 WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
277 vpd->zoom= sima->zoom;
279 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
282 static void view_zoom_exit(bContext *C, wmOperator *op, int cancel)
284 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
285 ViewZoomData *vpd= op->customdata;
288 sima->zoom= vpd->zoom;
289 ED_area_tag_redraw(CTX_wm_area(C));
292 WM_cursor_restore(CTX_wm_window(C));
293 MEM_freeN(op->customdata);
296 static int view_zoom_exec(bContext *C, wmOperator *op)
298 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
299 ARegion *ar= CTX_wm_region(C);
301 sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"));
303 ED_area_tag_redraw(CTX_wm_area(C));
307 if(image_preview_active(curarea, NULL, NULL)) {
308 /* recalculates new preview rect */
309 scrarea_do_windraw(curarea);
310 image_preview_event(2);
314 return OPERATOR_FINISHED;
317 static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
319 view_zoom_init(C, op, event);
320 return OPERATOR_RUNNING_MODAL;
323 static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
325 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
326 ARegion *ar= CTX_wm_region(C);
327 ViewZoomData *vpd= op->customdata;
330 switch(event->type) {
332 factor= 1.0 + (vpd->x-event->x+vpd->y-event->y)/300.0f;
333 RNA_float_set(op->ptr, "factor", factor);
334 sima_zoom_set(sima, ar, vpd->zoom*factor);
335 ED_area_tag_redraw(CTX_wm_area(C));
339 view_zoom_exit(C, op, 0);
340 return OPERATOR_FINISHED;
345 return OPERATOR_RUNNING_MODAL;
348 static int view_zoom_cancel(bContext *C, wmOperator *op)
350 view_zoom_exit(C, op, 1);
351 return OPERATOR_CANCELLED;
354 void IMAGE_OT_view_zoom(wmOperatorType *ot)
357 ot->name= "View Zoom";
358 ot->idname= "IMAGE_OT_view_zoom";
361 ot->exec= view_zoom_exec;
362 ot->invoke= view_zoom_invoke;
363 ot->modal= view_zoom_modal;
364 ot->cancel= view_zoom_cancel;
365 ot->poll= space_image_main_area_poll;
368 RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, FLT_MAX,
369 "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out.", -FLT_MAX, FLT_MAX);
372 /********************** view all operator *********************/
374 /* Updates the fields of the View2D member of the SpaceImage struct.
375 * Default behavior is to reset the position of the image and set the zoom to 1
376 * If the image will not fit within the window rectangle, the zoom is adjusted */
378 static int view_all_exec(bContext *C, wmOperator *op)
386 float aspx, aspy, zoomx, zoomy, w, h;
390 sima= (SpaceImage*)CTX_wm_space_data(C);
391 ar= CTX_wm_region(C);
392 scene= (Scene*)CTX_data_scene(C);
393 obedit= CTX_data_edit_object(C);
395 ima= ED_space_image(sima);
396 ibuf= ED_space_image_buffer(sima);
397 ED_space_image_size(sima, &width, &height);
398 ED_space_image_aspect(sima, &aspx, &aspy);
403 /* check if the image will fit in the image with zoom==1 */
404 width = ar->winrct.xmax - ar->winrct.xmin + 1;
405 height = ar->winrct.ymax - ar->winrct.ymin + 1;
407 if((w >= width || h >= height) && (width > 0 && height > 0)) {
408 /* find the zoom value that will fit the image in the image space */
411 sima_zoom_set(sima, ar, 1.0f/power_of_2(1/MIN2(zoomx, zoomy)));
414 sima_zoom_set(sima, ar, 1.0f);
416 sima->xof= sima->yof= 0.0f;
418 ED_area_tag_redraw(CTX_wm_area(C));
420 return OPERATOR_FINISHED;
423 void IMAGE_OT_view_all(wmOperatorType *ot)
426 ot->name= "View All";
427 ot->idname= "IMAGE_OT_view_all";
430 ot->exec= view_all_exec;
431 ot->poll= space_image_main_area_poll;
434 /********************** view selected operator *********************/
436 static int view_selected_exec(bContext *C, wmOperator *op)
444 float size, min[2], max[2], d[2];
448 sima= (SpaceImage*)CTX_wm_space_data(C);
449 ar= CTX_wm_region(C);
450 scene= (Scene*)CTX_data_scene(C);
451 obedit= CTX_data_edit_object(C);
453 ima= ED_space_image(sima);
454 ibuf= ED_space_image_buffer(sima);
455 ED_space_image_size(sima, &width, &height);
458 if(!ED_uvedit_minmax(scene, ima, obedit, min, max))
459 return OPERATOR_CANCELLED;
461 /* adjust offset and zoom */
462 sima->xof= (int)(((min[0] + max[0])*0.5f - 0.5f)*width);
463 sima->yof= (int)(((min[1] + max[1])*0.5f - 0.5f)*height);
465 d[0]= max[0] - min[0];
466 d[1]= max[1] - min[1];
467 size= 0.5*MAX2(d[0], d[1])*MAX2(width, height)/256.0f;
469 if(size<=0.01) size= 0.01;
470 sima_zoom_set(sima, ar, 0.7/size);
472 ED_area_tag_redraw(CTX_wm_area(C));
474 return OPERATOR_FINISHED;
477 void IMAGE_OT_view_selected(wmOperatorType *ot)
480 ot->name= "View Center";
481 ot->idname= "IMAGE_OT_view_selected";
484 ot->exec= view_selected_exec;
485 ot->poll= ED_operator_uvedit;
488 /********************** view zoom in/out operator *********************/
490 static int view_zoom_in_exec(bContext *C, wmOperator *op)
492 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
493 ARegion *ar= CTX_wm_region(C);
495 sima_zoom_set_factor(sima, ar, 1.25f);
497 ED_area_tag_redraw(CTX_wm_area(C));
499 return OPERATOR_FINISHED;
502 void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
505 ot->name= "View Zoom In";
506 ot->idname= "IMAGE_OT_view_zoom_in";
509 ot->exec= view_zoom_in_exec;
510 ot->poll= space_image_main_area_poll;
513 static int view_zoom_out_exec(bContext *C, wmOperator *op)
515 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
516 ARegion *ar= CTX_wm_region(C);
518 sima_zoom_set_factor(sima, ar, 0.8f);
520 ED_area_tag_redraw(CTX_wm_area(C));
522 return OPERATOR_FINISHED;
525 void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
528 ot->name= "View Zoom Out";
529 ot->idname= "IMAGE_OT_view_zoom_out";
532 ot->exec= view_zoom_out_exec;
533 ot->poll= space_image_main_area_poll;
536 /********************** view zoom ratio operator *********************/
538 static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
540 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
541 ARegion *ar= CTX_wm_region(C);
543 sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio"));
545 /* ensure pixel exact locations for draw */
546 sima->xof= (int)sima->xof;
547 sima->yof= (int)sima->yof;
551 if(image_preview_active(curarea, NULL, NULL)) {
552 /* recalculates new preview rect */
553 scrarea_do_windraw(curarea);
554 image_preview_event(2);
558 ED_area_tag_redraw(CTX_wm_area(C));
560 return OPERATOR_FINISHED;
563 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
566 ot->name= "View Zoom Ratio";
567 ot->idname= "IMAGE_OT_view_zoom_ratio";
570 ot->exec= view_zoom_ratio_exec;
571 ot->poll= space_image_main_area_poll;
574 RNA_def_float(ot->srna, "ratio", 0.0f, 0.0f, FLT_MAX,
575 "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out.", -FLT_MAX, FLT_MAX);
578 /**************** load/replace/save callbacks ******************/
580 /* XXX make dynamic */
581 static const EnumPropertyItem image_file_type_items[] = {
582 {R_TARGA, "TARGA", 0, "Targa", ""},
583 {R_RAWTGA, "TARGA RAW", 0, "Targa Raw", ""},
584 {R_PNG, "PNG", 0, "PNG", ""},
585 {R_BMP, "BMP", 0, "BMP", ""},
586 {R_JPEG90, "JPEG", 0, "Jpeg", ""},
588 {R_JP2, "JPEG_2000", 0, "Jpeg 2000", ""},
590 {R_IRIS, "IRIS", 0, "Iris", ""},
592 {R_TIFF, "TIFF", 0, "Tiff", ""},
593 {R_RADHDR, "RADIANCE_HDR", 0, "Radiance HDR", ""},
594 {R_CINEON, "CINEON", 0, "Cineon", ""},
595 {R_DPX, "DPX", 0, "DPX", ""},
597 {R_OPENEXR, "OPENEXR", 0, "OpenEXR", ""},
598 /* saving sequences of multilayer won't work, they copy buffers */
599 /*if(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER);
601 {R_MULTILAYER, "MULTILAYER", 0, "MultiLayer", ""},
603 {0, NULL, 0, NULL, NULL}};
605 static void image_filesel(bContext *C, wmOperator *op, const char *path)
607 RNA_string_set(op->ptr, "filename", path);
608 WM_event_add_fileselect(C, op);
611 /******************** open image operator ********************/
613 static int open_exec(bContext *C, wmOperator *op)
615 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
616 Scene *scene= CTX_data_scene(C);
617 Object *obedit= CTX_data_edit_object(C);
621 RNA_string_get(op->ptr, "filename", str);
622 ima= BKE_add_image_file(str, scene->r.cfra);
625 return OPERATOR_CANCELLED;
627 BKE_image_signal(ima, &sima->iuser, IMA_SIGNAL_RELOAD);
628 ED_space_image_set(C, sima, scene, obedit, ima);
630 return OPERATOR_FINISHED;
633 static int open_invoke(bContext *C, wmOperator *op, wmEvent *event)
635 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
636 char *path= (sima->image)? sima->image->name: U.textudir;
638 if(RNA_property_is_set(op->ptr, "filename"))
639 return open_exec(C, op);
641 image_filesel(C, op, path);
643 return OPERATOR_RUNNING_MODAL;
646 void IMAGE_OT_open(wmOperatorType *ot)
650 ot->idname= "IMAGE_OT_open";
654 ot->invoke= open_invoke;
655 ot->poll= ED_operator_image_active;
658 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
661 RNA_def_string_file_path(ot->srna, "filename", "", FILE_MAX, "Filename", "File path of image to open.");
664 /******************** replace image operator ********************/
666 static int replace_exec(bContext *C, wmOperator *op)
668 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
672 return OPERATOR_CANCELLED;
674 RNA_string_get(op->ptr, "filename", str);
675 BLI_strncpy(sima->image->name, str, sizeof(sima->image->name)-1); /* we cant do much if the str is longer then 240 :/ */
677 BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
678 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
680 return OPERATOR_FINISHED;
683 static int replace_invoke(bContext *C, wmOperator *op, wmEvent *event)
685 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
686 char *path= (sima->image)? sima->image->name: U.textudir;
689 return OPERATOR_CANCELLED;
691 if(RNA_property_is_set(op->ptr, "filename"))
692 return replace_exec(C, op);
694 image_filesel(C, op, path);
696 return OPERATOR_RUNNING_MODAL;
699 void IMAGE_OT_replace(wmOperatorType *ot)
703 ot->idname= "IMAGE_OT_replace";
706 ot->exec= replace_exec;
707 ot->invoke= replace_invoke;
708 ot->poll= space_image_poll;
711 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
714 RNA_def_string_file_path(ot->srna, "filename", "", FILE_MAX, "Filename", "File path of image to replace current image with.");
717 /******************** save image as operator ********************/
719 /* assumes name is FILE_MAX */
720 /* ima->name and ibuf->name should end up the same */
721 static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOperator *op, char *name)
723 Image *ima= ED_space_image(sima);
724 ImBuf *ibuf= ED_space_image_buffer(sima);
728 BLI_convertstringcode(name, G.sce);
729 BLI_convertstringframe(name, scene->r.cfra);
731 if(scene->r.scemode & R_EXTENSION) {
732 BKE_add_image_extension(scene, name, sima->imtypenr);
733 BKE_add_image_extension(scene, name, sima->imtypenr);
736 /* enforce user setting for RGB or RGBA, but skip BW */
737 if(scene->r.planes==32)
739 else if(scene->r.planes==24)
744 if(sima->imtypenr==R_MULTILAYER) {
745 RenderResult *rr= BKE_image_get_renderresult(scene, ima);
747 RE_WriteRenderResult(rr, name, scene->r.quality);
749 BLI_strncpy(ima->name, name, sizeof(ima->name));
750 BLI_strncpy(ibuf->name, name, sizeof(ibuf->name));
752 /* should be function? nevertheless, saving only happens here */
753 for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
754 ibuf->userflags &= ~IB_BITMAPDIRTY;
758 BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
760 else if (BKE_write_ibuf(scene, ibuf, name, sima->imtypenr, scene->r.subimtype, scene->r.quality)) {
761 BLI_strncpy(ima->name, name, sizeof(ima->name));
762 BLI_strncpy(ibuf->name, name, sizeof(ibuf->name));
764 ibuf->userflags &= ~IB_BITMAPDIRTY;
767 if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
768 ima->source= IMA_SRC_FILE;
769 ima->type= IMA_TYPE_IMAGE;
771 if(ima->type==IMA_TYPE_R_RESULT)
772 ima->type= IMA_TYPE_IMAGE;
774 /* name image as how we saved it */
776 while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\') len--;
777 rename_id(&ima->id, name+len);
780 BKE_reportf(op->reports, RPT_ERROR, "Couldn't write image: %s", name);
782 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
788 static int save_as_exec(bContext *C, wmOperator *op)
790 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
791 Scene *scene= CTX_data_scene(C);
792 Image *ima = ED_space_image(sima);
796 return OPERATOR_CANCELLED;
798 sima->imtypenr= RNA_enum_get(op->ptr, "file_type");
799 RNA_string_get(op->ptr, "filename", str);
801 save_image_doit(C, sima, scene, op, str);
803 return OPERATOR_FINISHED;
806 static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
808 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
809 Image *ima = ED_space_image(sima);
810 ImBuf *ibuf= ED_space_image_buffer(sima);
811 Scene *scene= CTX_data_scene(C);
813 if(RNA_property_is_set(op->ptr, "filename"))
814 return save_as_exec(C, op);
817 return OPERATOR_CANCELLED;
819 /* always opens fileselect */
821 /* cant save multilayer sequence, ima->rr isn't valid for a specific frame */
822 if(ima->rr && !(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER))
823 sima->imtypenr= R_MULTILAYER;
824 else if(ima->type==IMA_TYPE_R_RESULT)
825 sima->imtypenr= scene->r.imtype;
827 sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
829 RNA_enum_set(op->ptr, "file_type", sima->imtypenr);
832 BLI_strncpy(ibuf->name, G.ima, FILE_MAX);
834 // XXX note: we can give default menu enums to operator for this
835 image_filesel(C, op, ibuf->name);
837 return OPERATOR_RUNNING_MODAL;
840 return OPERATOR_CANCELLED;
843 void IMAGE_OT_save_as(wmOperatorType *ot)
847 ot->idname= "IMAGE_OT_save_as";
850 ot->exec= save_as_exec;
851 ot->invoke= save_as_invoke;
852 ot->poll= space_image_poll;
855 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
858 RNA_def_string_file_path(ot->srna, "filename", "", FILE_MAX, "Filename", "File path to save image to.");
859 RNA_def_enum(ot->srna, "file_type", image_file_type_items, R_PNG, "File Type", "File type to save image as.");
862 /******************** save image operator ********************/
864 static int save_exec(bContext *C, wmOperator *op)
866 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
867 Image *ima = ED_space_image(sima);
868 ImBuf *ibuf= ED_space_image_buffer(sima);
869 Scene *scene= CTX_data_scene(C);
873 return OPERATOR_CANCELLED;
875 /* if exists, saves over without fileselect */
877 BLI_strncpy(name, ibuf->name, FILE_MAX);
879 BLI_strncpy(name, G.ima, FILE_MAX);
881 if(BLI_exists(name) && BLI_is_writable(name)) {
882 if(BKE_image_get_renderresult(scene, ima))
883 sima->imtypenr= R_MULTILAYER;
885 sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
887 save_image_doit(C, sima, scene, op, name);
890 BKE_report(op->reports, RPT_ERROR, "Can not save image.");
891 return OPERATOR_CANCELLED;
894 return OPERATOR_FINISHED;
897 void IMAGE_OT_save(wmOperatorType *ot)
901 ot->idname= "IMAGE_OT_save";
905 ot->poll= space_image_file_exists_poll;
908 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
911 /******************* save sequence operator ********************/
913 static int save_sequence_exec(bContext *C, wmOperator *op)
915 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
918 char di[FILE_MAX], fi[FILE_MAX];
920 if(sima->image==NULL)
921 return OPERATOR_CANCELLED;
923 if(sima->image->source!=IMA_SRC_SEQUENCE) {
924 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences.");
925 return OPERATOR_CANCELLED;
928 if(sima->image->type==IMA_TYPE_MULTILAYER) {
929 BKE_report(op->reports, RPT_ERROR, "Can't save multilayer sequences.");
930 return OPERATOR_CANCELLED;
934 for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next)
935 if(ibuf->userflags & IB_BITMAPDIRTY)
939 BKE_report(op->reports, RPT_WARNING, "No images have been changed.");
940 return OPERATOR_CANCELLED;
943 /* get a filename for menu */
944 for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next)
945 if(ibuf->userflags & IB_BITMAPDIRTY)
948 BLI_strncpy(di, ibuf->name, FILE_MAX);
949 BLI_splitdirstring(di, fi);
951 BKE_reportf(op->reports, RPT_INFO, "%d Image(s) will be saved in %s", tot, di);
953 for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) {
954 if(ibuf->userflags & IB_BITMAPDIRTY) {
956 BLI_strncpy(name, ibuf->name, sizeof(name));
958 BLI_convertstringcode(name, G.sce);
960 if(0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
961 BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s.", name);
965 printf("Saved: %s\n", ibuf->name);
966 ibuf->userflags &= ~IB_BITMAPDIRTY;
970 return OPERATOR_FINISHED;
973 void IMAGE_OT_save_sequence(wmOperatorType *ot)
976 ot->name= "Save Sequence";
977 ot->idname= "IMAGE_OT_save_sequence";
980 ot->exec= save_sequence_exec;
981 ot->poll= space_image_poll;
984 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
987 /******************** reload image operator ********************/
989 static int reload_exec(bContext *C, wmOperator *op)
994 sima= (SpaceImage*)CTX_wm_space_data(C);
997 return OPERATOR_CANCELLED;
999 BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
1000 /* ED_space_image_set(C, sima, scene, obedit, NULL); - do we really need this? */
1002 // XXX BIF_preview_changed(ID_TE);
1003 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
1004 ED_area_tag_redraw(CTX_wm_area(C));
1006 return OPERATOR_FINISHED;
1009 void IMAGE_OT_reload(wmOperatorType *ot)
1013 ot->idname= "IMAGE_OT_reload";
1016 ot->exec= reload_exec;
1017 ot->poll= space_image_poll;
1020 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1023 /********************** new image operator *********************/
1025 static int new_exec(bContext *C, wmOperator *op)
1033 int width, height, floatbuf, uvtestgrid;
1035 /* retrieve state */
1036 sima= (SpaceImage*)CTX_wm_space_data(C);
1037 scene= (Scene*)CTX_data_scene(C);
1038 obedit= CTX_data_edit_object(C);
1040 RNA_string_get(op->ptr, "name", name);
1041 width= RNA_int_get(op->ptr, "width");
1042 height= RNA_int_get(op->ptr, "height");
1043 floatbuf= RNA_boolean_get(op->ptr, "float");
1044 uvtestgrid= RNA_boolean_get(op->ptr, "uv_test_grid");
1045 RNA_float_get_array(op->ptr, "color", color);
1046 color[3]= RNA_float_get(op->ptr, "alpha");
1048 ima = BKE_add_image_size(width, height, name, floatbuf, uvtestgrid, color);
1049 BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE);
1050 ED_space_image_set(C, sima, scene, obedit, ima);
1052 return OPERATOR_FINISHED;
1055 void IMAGE_OT_new(wmOperatorType *ot)
1059 ot->idname= "IMAGE_OT_new";
1063 ot->invoke= WM_operator_redo;
1064 ot->poll= ED_operator_image_active;
1067 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1070 RNA_def_string(ot->srna, "name", "Untitled", 21, "Name", "Image datablock name.");
1071 RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width.", 1, 16384);
1072 RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height.", 1, 16384);
1073 RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0f, FLT_MAX, "Color", "Default fill color.", 0.0f, 1.0f);
1074 RNA_def_float(ot->srna, "alpha", 1.0f, 0.0f, 1.0f, "Alpha", "Default fill alpha.", 0.0f, 1.0f);
1075 RNA_def_boolean(ot->srna, "uv_test_grid", 0, "UV Test Grid", "Fill the image with a grid for UV map testing.");
1076 RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth.");
1079 /********************* pack operator *********************/
1081 static int pack_test(bContext *C, wmOperator *op)
1083 Image *ima= CTX_data_edit_image(C);
1084 int as_png= RNA_boolean_get(op->ptr, "as_png");
1088 if(!as_png && ima->packedfile)
1091 if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
1092 BKE_report(op->reports, RPT_ERROR, "Can't pack movie or image sequence.");
1099 static int pack_exec(bContext *C, wmOperator *op)
1101 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
1102 Image *ima= ED_space_image(sima);
1103 ImBuf *ibuf= ED_space_image_buffer(sima);
1104 int as_png= RNA_boolean_get(op->ptr, "as_png");
1106 if(!pack_test(C, op))
1107 return OPERATOR_CANCELLED;
1109 if(!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
1110 BKE_report(op->reports, RPT_ERROR, "Can't pack edited image from disk, only as internal PNG.");
1111 return OPERATOR_CANCELLED;
1115 BKE_image_memorypack(ima);
1117 ima->packedfile= newPackedFile(ima->name);
1119 return OPERATOR_FINISHED;
1122 static int pack_invoke(bContext *C, wmOperator *op, wmEvent *event)
1124 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
1125 ImBuf *ibuf= ED_space_image_buffer(sima);
1128 int as_png= RNA_boolean_get(op->ptr, "as_png");
1130 if(!pack_test(C, op))
1131 return OPERATOR_CANCELLED;
1133 if(!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
1134 pup= uiPupMenuBegin(C, "OK", ICON_QUESTION);
1135 layout= uiPupMenuLayout(pup);
1136 uiItemBooleanO(layout, "Can't pack edited image from disk. Pack as internal PNG?", 0, op->idname, "as_png", 1);
1137 uiPupMenuEnd(C, pup);
1139 return OPERATOR_CANCELLED;
1142 return pack_exec(C, op);
1145 void IMAGE_OT_pack(wmOperatorType *ot)
1149 ot->idname= "IMAGE_OT_pack";
1152 ot->exec= pack_exec;
1153 ot->invoke= pack_invoke;
1154 ot->poll= space_image_poll;
1157 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1160 RNA_def_boolean(ot->srna, "as_png", 0, "Pack As PNG", "Pack image as lossless PNG.");
1163 /********************* unpack operator *********************/
1165 static int unpack_exec(bContext *C, wmOperator *op)
1167 Image *ima= CTX_data_edit_image(C);
1170 return OPERATOR_CANCELLED;
1171 if(!ima->packedfile)
1172 return OPERATOR_CANCELLED;
1174 if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
1175 BKE_report(op->reports, RPT_ERROR, "Can't unpack movie or image sequence.");
1176 return OPERATOR_CANCELLED;
1179 if(G.fileflags & G_AUTOPACK)
1180 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
1182 unpackImage(ima, PF_ASK);
1184 return OPERATOR_FINISHED;
1187 void IMAGE_OT_unpack(wmOperatorType *ot)
1191 ot->idname= "IMAGE_OT_unpack";
1194 ot->exec= unpack_exec;
1195 ot->poll= space_image_poll;
1198 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1201 /******************** sample image operator ********************/
1203 typedef struct ImageSampleInfo {
1221 static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
1223 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
1224 ImBuf *ibuf= ED_space_image_buffer(sima);
1225 ImageSampleInfo *info= arg_info;
1230 draw_image_info(ar, ibuf->channels, info->x, info->y, info->colp,
1231 info->colfp, info->zp, info->zfp);
1234 static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
1236 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
1237 ARegion *ar= CTX_wm_region(C);
1238 ImBuf *ibuf= ED_space_image_buffer(sima);
1239 ImageSampleInfo *info= op->customdata;
1246 x= event->x - ar->winrct.xmin;
1247 y= event->y - ar->winrct.ymin;
1248 UI_view2d_region_to_view(&ar->v2d, x, y, &fx, &fy);
1250 if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
1253 int x= (int)(fx*ibuf->x), y= (int)(fy*ibuf->y);
1255 CLAMP(x, 0, ibuf->x-1);
1256 CLAMP(y, 0, ibuf->y-1);
1268 cp= (char *)(ibuf->rect + y*ibuf->x + x);
1270 info->col[0]= cp[0];
1271 info->col[1]= cp[1];
1272 info->col[2]= cp[2];
1273 info->col[3]= cp[3];
1274 info->colp= info->col;
1276 info->colf[0]= (float)cp[0]/255.0f;
1277 info->colf[1]= (float)cp[1]/255.0f;
1278 info->colf[2]= (float)cp[2]/255.0f;
1279 info->colf[3]= (float)cp[3]/255.0f;
1280 info->colfp= info->colf;
1282 if(ibuf->rect_float) {
1283 fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
1285 info->colf[0]= fp[0];
1286 info->colf[1]= fp[1];
1287 info->colf[2]= fp[2];
1288 info->colf[3]= fp[4];
1289 info->colfp= info->colf;
1293 info->z= ibuf->zbuf[y*ibuf->x + x];
1296 if(ibuf->zbuf_float) {
1297 info->zf= ibuf->zbuf_float[y*ibuf->x + x];
1298 info->zfp= &info->zf;
1301 if(sima->cumap && ibuf->channels==4) {
1302 /* we reuse this callback for set curves point operators */
1303 if(RNA_struct_find_property(op->ptr, "point")) {
1304 int point= RNA_enum_get(op->ptr, "point");
1307 curvemapping_set_black_white(sima->cumap, NULL, info->colfp);
1308 curvemapping_do_ibuf(sima->cumap, ibuf);
1310 else if(point == 0) {
1311 curvemapping_set_black_white(sima->cumap, info->colfp, NULL);
1312 curvemapping_do_ibuf(sima->cumap, ibuf);
1317 // XXX node curve integration ..
1320 ScrArea *sa, *cur= curarea;
1322 node_curvemap_sample(fp); /* sends global to node editor */
1323 for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1324 if(sa->spacetype==SPACE_NODE) {
1325 areawinset(sa->win);
1326 scrarea_do_windraw(sa);
1329 node_curvemap_sample(NULL); /* clears global in node editor */
1337 ED_area_tag_redraw(CTX_wm_area(C));
1340 static void sample_exit(bContext *C, wmOperator *op)
1342 ImageSampleInfo *info= op->customdata;
1344 ED_region_draw_cb_exit(info->art, info->draw_handle);
1345 ED_area_tag_redraw(CTX_wm_area(C));
1349 static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
1351 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
1352 ARegion *ar= CTX_wm_region(C);
1353 ImBuf *ibuf= ED_space_image_buffer(sima);
1354 ImageSampleInfo *info;
1357 return OPERATOR_CANCELLED;
1359 info= MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
1360 info->art= ar->type;
1361 info->draw_handle = ED_region_draw_cb_activate(ar->type, sample_draw, info, REGION_DRAW_POST);
1362 op->customdata= info;
1364 sample_apply(C, op, event);
1366 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1368 return OPERATOR_RUNNING_MODAL;
1371 static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
1373 switch(event->type) {
1375 case RIGHTMOUSE: // XXX hardcoded
1377 return OPERATOR_CANCELLED;
1379 sample_apply(C, op, event);
1383 return OPERATOR_RUNNING_MODAL;
1386 static int sample_cancel(bContext *C, wmOperator *op)
1389 return OPERATOR_CANCELLED;
1392 void IMAGE_OT_sample(wmOperatorType *ot)
1396 ot->idname= "IMAGE_OT_sample";
1399 ot->invoke= sample_invoke;
1400 ot->modal= sample_modal;
1401 ot->cancel= sample_cancel;
1402 ot->poll= space_image_main_area_poll;
1405 /******************** set curve point operator ********************/
1407 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
1409 static EnumPropertyItem point_items[]= {
1410 {0, "BLACK_POINT", 0, "Black Point", ""},
1411 {1, "WHITE_POINT", 0, "White Point", ""},
1412 {0, NULL, 0, NULL, NULL}};
1415 ot->name= "Set Curves Point";
1416 ot->idname= "IMAGE_OT_curves_point_set";
1419 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1422 ot->invoke= sample_invoke;
1423 ot->modal= sample_modal;
1424 ot->cancel= sample_cancel;
1425 ot->poll= space_image_main_area_poll;
1428 RNA_def_enum(ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves.");
1431 /******************** record composite operator *********************/
1433 typedef struct RecordCompositeData {
1437 } RecordCompositeData;
1439 int record_composite_apply(bContext *C, wmOperator *op)
1441 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
1442 RecordCompositeData *rcd= op->customdata;
1443 Scene *scene= CTX_data_scene(C);
1446 WM_timecursor(CTX_wm_window(C), scene->r.cfra);
1448 // XXX scene->nodetree->test_break= blender_test_break;
1449 // XXX scene->nodetree->test_break= NULL;
1451 BKE_image_all_free_anim_ibufs(scene->r.cfra);
1452 ntreeCompositTagAnimated(scene->nodetree);
1453 ntreeCompositExecTree(scene->nodetree, &scene->r, scene->r.cfra != rcd->old_cfra); /* 1 is no previews */
1455 ED_area_tag_redraw(CTX_wm_area(C));
1457 ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
1458 /* save memory in flipbooks */
1460 imb_freerectfloatImBuf(ibuf);
1464 return (scene->r.cfra <= rcd->efra);
1467 static int record_composite_init(bContext *C, wmOperator *op)
1469 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
1470 Scene *scene= CTX_data_scene(C);
1471 RecordCompositeData *rcd;
1473 if(sima->iuser.frames < 2)
1475 if(scene->nodetree == NULL)
1478 op->customdata= rcd= MEM_callocN(sizeof(RecordCompositeData), "ImageRecordCompositeData");
1480 rcd->old_cfra= scene->r.cfra;
1481 rcd->sfra= sima->iuser.sfra;
1482 rcd->efra= sima->iuser.sfra + sima->iuser.frames-1;
1483 scene->r.cfra= rcd->sfra;
1488 static void record_composite_exit(bContext *C, wmOperator *op)
1490 Scene *scene= CTX_data_scene(C);
1491 SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
1492 RecordCompositeData *rcd= op->customdata;
1494 scene->r.cfra= rcd->old_cfra;
1496 WM_cursor_restore(CTX_wm_window(C));
1499 WM_event_remove_window_timer(CTX_wm_window(C), rcd->timer);
1501 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
1503 // XXX play_anim(0);
1504 // XXX allqueue(REDRAWNODE, 1);
1509 static int record_composite_exec(bContext *C, wmOperator *op)
1511 if(!record_composite_init(C, op))
1512 return OPERATOR_CANCELLED;
1514 while(record_composite_apply(C, op))
1517 record_composite_exit(C, op);
1519 return OPERATOR_FINISHED;
1522 static int record_composite_invoke(bContext *C, wmOperator *op, wmEvent *event)
1524 RecordCompositeData *rcd= op->customdata;
1526 if(!record_composite_init(C, op))
1527 return OPERATOR_CANCELLED;
1529 rcd= op->customdata;
1530 rcd->timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER, 0.0f);
1531 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1533 if(!record_composite_apply(C, op))
1534 return OPERATOR_FINISHED;
1536 return OPERATOR_RUNNING_MODAL;
1539 static int record_composite_modal(bContext *C, wmOperator *op, wmEvent *event)
1541 RecordCompositeData *rcd= op->customdata;
1543 switch(event->type) {
1545 if(rcd->timer == event->customdata) {
1546 if(!record_composite_apply(C, op)) {
1547 record_composite_exit(C, op);
1548 return OPERATOR_FINISHED;
1553 record_composite_exit(C, op);
1554 return OPERATOR_FINISHED;
1557 return OPERATOR_RUNNING_MODAL;
1560 static int record_composite_cancel(bContext *C, wmOperator *op)
1562 record_composite_exit(C, op);
1563 return OPERATOR_CANCELLED;
1566 void IMAGE_OT_record_composite(wmOperatorType *ot)
1569 ot->name= "Record Composite";
1570 ot->idname= "IMAGE_OT_record_composite";
1573 ot->exec= record_composite_exec;
1574 ot->invoke= record_composite_invoke;
1575 ot->modal= record_composite_modal;
1576 ot->cancel= record_composite_cancel;
1577 ot->poll= space_image_poll;
1580 /******************** TODO ********************/
1584 /* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
1585 void BIF_image_update_frame(void)
1590 for(tex= G.main->tex.first; tex; tex= tex->id.next) {
1591 if(tex->type==TEX_IMAGE && tex->ima)
1592 if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
1593 if(tex->iuser.flag & IMA_ANIM_ALWAYS)
1594 BKE_image_user_calc_imanr(&tex->iuser, scene->r.cfra, 0);
1597 /* image window, compo node users */
1600 for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1601 if(sa->spacetype==SPACE_VIEW3D) {
1602 View3D *v3d= sa->spacedata.first;
1604 if(v3d->bgpic->iuser.flag & IMA_ANIM_ALWAYS)
1605 BKE_image_user_calc_imanr(&v3d->bgpic->iuser, scene->r.cfra, 0);
1607 else if(sa->spacetype==SPACE_IMAGE) {
1608 SpaceImage *sima= sa->spacedata.first;
1609 if(sima->iuser.flag & IMA_ANIM_ALWAYS)
1610 BKE_image_user_calc_imanr(&sima->iuser, scene->r.cfra, 0);
1612 else if(sa->spacetype==SPACE_NODE) {
1613 SpaceNode *snode= sa->spacedata.first;
1614 if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) {
1616 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1617 if(node->id && node->type==CMP_NODE_IMAGE) {
1618 Image *ima= (Image *)node->id;
1619 ImageUser *iuser= node->storage;
1620 if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
1621 if(iuser->flag & IMA_ANIM_ALWAYS)
1622 BKE_image_user_calc_imanr(iuser, scene->r.cfra, 0);