Support for loading multiple images from the file selector

D2035 by @jside, extended to support mixing single images and sequences in the one selection.
This commit is contained in:
Campbell Barton
2016-07-15 16:02:46 +10:00
parent e56aa5d788
commit ccee251a40

View File

@@ -1061,6 +1061,12 @@ typedef struct ImageOpenData {
ImageFormatData im_format;
} ImageOpenData;
typedef struct ImageFrameRange {
struct ImageFrameRange *next, *prev;
ListBase frames;
char filepath[FILE_MAX];
} ImageFrameRange;
typedef struct ImageFrame {
struct ImageFrame *next, *prev;
int framenr;
@@ -1086,10 +1092,10 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
* \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)
static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
{
char dir[FILE_MAXDIR];
bool is_first_entry = true;
ImageFrameRange *frame_range = NULL;
RNA_string_get(ptr, "directory", dir);
RNA_BEGIN (ptr, itemptr, "files")
@@ -1101,29 +1107,26 @@ static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *p
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;
frame->framenr = BLI_stringdec(filename, head, tail, &digits);
/* still in the same sequence */
if ((frame_range != NULL) &&
(STREQLEN(base_head, head, FILE_MAX)) &&
(STREQLEN(base_tail, tail, FILE_MAX)))
{
/* pass */
}
else {
frame->framenr = BLI_stringdec(filename, head, tail, &digits);
/* start a new frame range */
frame_range = MEM_callocN(sizeof(*frame_range), __func__);
BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename);
BLI_addtail(frames_all, frame_range);
/* 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(filename);
MEM_freeN(frame);
break;
}
BLI_strncpy(base_head, head, sizeof(base_head));
BLI_strncpy(base_tail, tail, sizeof(base_tail));
}
BLI_addtail(&frame_range->frames, frame);
MEM_freeN(filename);
}
RNA_END
@@ -1164,6 +1167,52 @@ static int image_sequence_get_len(ListBase *frames, int *ofs)
return 0;
}
static Image *image_open_single(
wmOperator *op, const char *filepath, const char *relbase,
bool is_relative_path, bool use_multiview, int frame_seq_len)
{
bool exists = false;
Image *ima = NULL;
errno = 0;
ima = BKE_image_load_exists_ex(filepath, &exists);
if (!ima) {
if (op->customdata) MEM_freeN(op->customdata);
BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
filepath, errno ? strerror(errno) : TIP_("unsupported image format"));
return NULL;
}
if (!exists) {
/* only image path after save, never ibuf */
if (is_relative_path) {
BLI_path_rel(ima->name, relbase);
}
/* handle multiview images */
if (use_multiview) {
ImageOpenData *iod = op->customdata;
ImageFormatData *imf = &iod->im_format;
ima->flag |= IMA_USE_VIEWS;
ima->views_format = imf->views_format;
*ima->stereo3d_format = imf->stereo3d_format;
}
else {
ima->flag &= ~IMA_USE_VIEWS;
BKE_image_free_views(ima);
}
if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
ima->source = IMA_SRC_SEQUENCE;
}
}
return ima;
}
static int image_open_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -1174,70 +1223,60 @@ static int image_open_exec(bContext *C, wmOperator *op)
ImageOpenData *iod = op->customdata;
PointerRNA idptr;
Image *ima = NULL;
char path[FILE_MAX];
char filepath[FILE_MAX];
int frame_seq_len = 0;
int frame_ofs = 1;
bool exists = false;
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
RNA_string_get(op->ptr, "filepath", path);
if (RNA_struct_property_is_set(op->ptr, "directory") &&
RNA_struct_property_is_set(op->ptr, "files"))
{
/* only to pass to imbuf */
char path_full[FILE_MAX];
BLI_strncpy(path_full, path, sizeof(path_full));
BLI_path_abs(path_full, G.main->name);
if (!IMB_isanim(path_full)) {
bool was_relative = BLI_path_is_rel(path);
ListBase frames;
BLI_listbase_clear(&frames);
image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
BLI_freelistN(&frames);
if (was_relative) {
BLI_path_rel(path, G.main->name);
}
}
}
errno = 0;
ima = BKE_image_load_exists_ex(path, &exists);
if (!ima) {
if (op->customdata) MEM_freeN(op->customdata);
BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
path, errno ? strerror(errno) : TIP_("unsupported image format"));
return OPERATOR_CANCELLED;
}
const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
if (!op->customdata)
image_open_init(C, op);
/* handle multiview images */
if (RNA_boolean_get(op->ptr, "use_multiview")) {
ImageFormatData *imf = &iod->im_format;
RNA_string_get(op->ptr, "filepath", filepath);
ima->flag |= IMA_USE_VIEWS;
ima->views_format = imf->views_format;
*ima->stereo3d_format = imf->stereo3d_format;
if (RNA_struct_property_is_set(op->ptr, "directory") &&
RNA_struct_property_is_set(op->ptr, "files"))
{
bool was_relative = BLI_path_is_rel(filepath);
ListBase frame_ranges_all;
BLI_listbase_clear(&frame_ranges_all);
image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all);
for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range; frame_range = frame_range->next) {
int frame_range_ofs;
int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs);
BLI_freelistN(&frame_range->frames);
char filepath_range[FILE_MAX];
BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
if (was_relative) {
BLI_path_rel(filepath_range, bmain->name);
}
Image *ima_range = image_open_single(
op, filepath_range, bmain->name,
is_relative_path, use_multiview, frame_range_seq_len);
/* take the first image */
if ((ima == NULL) && ima_range) {
ima = ima_range;
frame_seq_len = frame_range_seq_len;
frame_ofs = frame_range_ofs;
}
}
BLI_freelistN(&frame_ranges_all);
}
else {
ima->flag &= ~IMA_USE_VIEWS;
BKE_image_free_views(ima);
/* for drag & drop etc. */
ima = image_open_single(
op, filepath, bmain->name,
is_relative_path, use_multiview, 1);
}
/* only image path after save, never ibuf */
if (is_relative_path) {
if (!exists) {
BLI_path_rel(ima->name, bmain->name);
}
if (ima == NULL) {
return OPERATOR_CANCELLED;
}
/* hook into UI */
@@ -1245,11 +1284,8 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iod->pprop.prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
* pointer also increases user, so this compensates it */
id_us_min(&ima->id);
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(&iod->pprop.ptr, iod->pprop.prop, idptr);
RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);