[Bf-blender-cvs] [04f81c8] master: Fix T37481: Image Sequence can't be loaded

Andrea Weikert noreply at git.blender.org
Mon Jan 20 19:17:53 CET 2014


Commit: 04f81c8225f28ba9722cc06dc7f2d8a4d72a3fa3
Author: Andrea Weikert
Date:   Mon Jan 20 18:54:03 2014 +0100
https://developer.blender.org/rB04f81c8225f28ba9722cc06dc7f2d8a4d72a3fa3

Fix T37481: Image Sequence can't be loaded

Allow loading of image sequences in addition to single images in the open image operator

I solved it by adding the possibility to load an image sequence in the Load Image Operator.
The image user is passed in the operator customdata now as well, best solution for now, but general handling of image user still a bit weak. The offset and length of the image sequence is now calculated in the image open operator by storing all found frames in a list and sorting this list.

Reviewed By: campbellbarton, brecht, lukastoenne

Differential Revision: https://developer.blender.org/D209

===================================================================

M	source/blender/editors/space_image/image_ops.c
M	source/blender/editors/space_node/drawnode.c

===================================================================

diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index c2046e6..b4d98b0 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -915,12 +915,23 @@ static void image_filesel(bContext *C, wmOperator *op, const char *path)
 
 /******************** open image operator ********************/
 
+typedef struct ImageOpenData {
+	PropertyPointerRNA pprop;
+	ImageUser *iuser;
+} ImageOpenData;
+
+typedef struct ImageFrame {
+	struct ImageFrame *next, *prev;
+	int framenr;
+} ImageFrame;
+
 static void image_open_init(bContext *C, wmOperator *op)
 {
-	PropertyPointerRNA *pprop;
+	ImageOpenData *iod;
 
-	op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
-	uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
+	op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
+	iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
+	uiIDContextProperty(C, &iod->pprop.ptr, &iod->pprop.prop);
 }
 
 static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
@@ -929,45 +940,145 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
 	op->customdata = NULL;
 }
 
+/**
+ * @brief Get a list of frames from the list of image files matching the first file name sequence pattern
+ * @param ptr [in] the RNA pointer containing the "directory" entry and "files" collection
+ * @param frames [out] the list of frame numbers found in the files matching the first one by name
+ * @param path [out] the full path of the first file in the list of image files
+ */
+static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen)
+{
+	char dir[FILE_MAXDIR];
+	bool is_first_entry = true;
+
+	RNA_string_get(ptr, "directory", dir);
+	RNA_BEGIN (ptr, itemptr, "files")
+	{
+		char base_head[FILE_MAX], base_tail[FILE_MAX];
+		char head[FILE_MAX], tail[FILE_MAX];
+		unsigned short digits;
+		char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+		ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
+
+		/* use the first file in the list as base filename */
+		if (is_first_entry) {
+			BLI_join_dirfile(path, maxlen, dir, filename);
+			frame->framenr = BLI_stringdec(filename, base_head, base_tail, &digits);
+			BLI_addtail(frames, frame);
+			is_first_entry = false;
+		}
+		else {
+			frame->framenr = BLI_stringdec(filename, head, tail, &digits);
+
+			/* still in the same sequence */
+			if ((STREQLEN(base_head, head, FILE_MAX)) &&
+				(STREQLEN(base_tail, tail, FILE_MAX)))
+			{
+				BLI_addtail(frames, frame);
+			}
+			else {
+				/* different file base name found, is ignored */
+				MEM_freeN(frame);
+				break;
+			}
+		}
+
+		MEM_freeN(filename);
+	}
+	RNA_END
+}
+
+static int image_cmp_frame(void *a, void *b)
+{
+	ImageFrame *frame_a = (ImageFrame *)a;
+	ImageFrame *frame_b = (ImageFrame *)b;
+
+	if (frame_a->framenr < frame_b->framenr) return -1;
+	if (frame_a->framenr > frame_b->framenr) return 1;
+	return 0;
+}
+
+/**
+ * @brief Return the start (offset) and the length of the sequence of continuous frames in the list of frames
+ * @param frames [in] the list of frame numbers, as a side-effect the list is sorted
+ * @param ofs [out] offest, the first frame number in the sequence
+ * @return the number of continuos frames in the sequence
+ */
+static int image_sequence_get_len(ListBase *frames, int *ofs)
+{
+	ImageFrame *frame;
+
+	BLI_sortlist(frames, image_cmp_frame);
+
+	frame = frames->first;
+	if (frame) {
+		int frame_curr = frame->framenr;
+		(*ofs) = frame_curr;
+		while (frame && (frame->framenr == frame_curr)) {
+			frame_curr++;
+			frame = frame->next;
+		}
+		return frame_curr - (*ofs);
+	}
+	return 0;
+}
+
 static int image_open_exec(bContext *C, wmOperator *op)
 {
 	SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
 	Scene *scene = CTX_data_scene(C);
 	Object *obedit = CTX_data_edit_object(C);
 	ImageUser *iuser = NULL;
-	PropertyPointerRNA *pprop;
+	ImageOpenData *iod;
 	PointerRNA idptr;
 	Image *ima = NULL;
-	char str[FILE_MAX];
+	char path[FILE_MAX];
+	int frame_seq_len = 0;
+	int frame_ofs = 1;
 
-	RNA_string_get(op->ptr, "filepath", str);
-	/* default to frame 1 if there's no scene in context */
+	if (RNA_struct_property_is_set(op->ptr, "files") && RNA_struct_property_is_set(op->ptr, "directory")) {	
+		ListBase frames;
+
+		frames.first = frames.last = NULL;
+		image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
+		frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
+		BLI_freelistN(&frames);
+	}
+	else {
+		RNA_string_get(op->ptr, "filepath", path);
+	}
 
 	errno = 0;
 
-	ima = BKE_image_load_exists(str);
+	ima = BKE_image_load_exists(path);
 
 	if (!ima) {
 		if (op->customdata) MEM_freeN(op->customdata);
 		BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
-		            str, errno ? strerror(errno) : TIP_("unsupported image format"));
+		            path, errno ? strerror(errno) : TIP_("unsupported image format"));
 		return OPERATOR_CANCELLED;
 	}
-	
+
 	if (!op->customdata)
 		image_open_init(C, op);
 
 	/* hook into UI */
-	pprop = op->customdata;
+	iod = op->customdata;
 
-	if (pprop->prop) {
+	if (iod->pprop.prop) {
 		/* when creating new ID blocks, use is already 1, but RNA
 		 * pointer se also increases user, so this compensates it */
 		ima->id.us--;
-
+		if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) {
+			ima->source = IMA_SRC_SEQUENCE;
+		}
 		RNA_id_pointer_create(&ima->id, &idptr);
-		RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
-		RNA_property_update(C, &pprop->ptr, pprop->prop);
+		RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr);
+		RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
+	}
+
+	if (iod->iuser) {
+		iuser = iod->iuser;
 	}
 	else if (sima) {
 		ED_space_image_set(sima, scene, obedit, ima);
@@ -975,15 +1086,17 @@ static int image_open_exec(bContext *C, wmOperator *op)
 	}
 	else {
 		Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
-		if (tex && tex->type == TEX_IMAGE)
+		if (tex && tex->type == TEX_IMAGE) {
 			iuser = &tex->iuser;
-		
+		}
 	}
-	
+
 	/* initialize because of new image */
 	if (iuser) {
+		iuser->frames = frame_seq_len;
 		iuser->sfra = 1;
-		iuser->offset = 0;
+		iuser->framenr = 1;
+		iuser->offset = frame_ofs - 1;
 		iuser->fie_ima = 2;
 	}
 
@@ -1065,7 +1178,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
 
 	/* properties */
 	WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE,
-	                               WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
+	                               WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
 }
 
 /******************** Match movie length operator ********************/
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index c30c4fe..e8547b7 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -659,6 +659,8 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
 		/* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */
 		Scene *scene = CTX_data_scene(C);
 		ImageUser *iuser = iuserptr->data;
+		Image *ima = imaptr->data;
+
 		char numstr[32];
 		const int framenr = BKE_image_user_frame_get(iuser, CFRA, 0, NULL);
 		BLI_snprintf(numstr, sizeof(numstr), IFACE_("Frame: %d"), framenr);
@@ -773,6 +775,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
 	PointerRNA imaptr = RNA_pointer_get(ptr, "image");
 	PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
 
+	uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
 	uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
 	uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
 	uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
@@ -798,6 +801,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
 	PointerRNA imaptr = RNA_pointer_get(ptr, "image");
 	PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
 
+	uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
 	uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
 	uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
 	uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
@@ -1103,13 +1107,13 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
 	bNode *node = ptr->data;
 	PointerRNA imaptr, iuserptr;
 	
+	RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr);
+	uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
 	uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
-	
 	if (!node->id) return;
 	
 	imaptr = RNA_pointer_get(ptr, "image");
-	RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr);
-	
+
 	node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr);
 }
 
@@ -1119,6 +1123,7 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN
 	PointerRNA iuserptr;
 
 	RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr);
+	uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
 	uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0);
 }




More information about the Bf-blender-cvs mailing list