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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user