Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2020-02-07 02:01:50 +0300
committerBrecht Van Lommel <brecht@blender.org>2020-02-26 21:22:42 +0300
commitda38cb622e0f2e6389fee3ffb148ca77b5979014 (patch)
treec153731e6acf1c0260ca15bab556ff94443e5307 /source/blender/editors
parent4c4e798f3529b3972d96ad68635b3e31eccdee81 (diff)
Cleanup: split image sequence detection into own file, and make it reusable
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/include/ED_image.h26
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_image/image_ops.c274
-rw-r--r--source/blender/editors/space_image/image_sequence.c249
4 files changed, 295 insertions, 255 deletions
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index e6d8684a8b2..d78c2620253 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -24,15 +24,21 @@
#ifndef __ED_IMAGE_H__
#define __ED_IMAGE_H__
+#include "DNA_listBase.h"
+#include "DNA_space_types.h"
+
struct ARegion;
struct ImBuf;
struct Image;
struct ImageUser;
+struct LinkNodePair;
+struct Main;
struct ReportList;
struct Scene;
struct SpaceImage;
struct ViewLayer;
struct bContext;
+struct wmOperator;
struct wmWindowManager;
/* image_edit.c, exported for transform */
@@ -116,4 +122,24 @@ bool ED_image_should_save_modified(const struct bContext *C);
int ED_image_save_all_modified_info(const struct bContext *C, struct ReportList *reports);
bool ED_image_save_all_modified(const struct bContext *C, struct ReportList *reports);
+/* image_sequence.c */
+typedef struct ImageFrameRange {
+ struct ImageFrameRange *next, *prev;
+
+ /** Absolute file path of the first file in the range. */
+ char filepath[FILE_MAX];
+ /* Sequence parameters. */
+ int length;
+ int offset;
+ /* UDIM tiles. */
+ ListBase udim_tiles;
+
+ /* Temporary data. */
+ ListBase frames;
+} ImageFrameRange;
+
+ListBase ED_image_filesel_detect_sequences(struct Main *bmain,
+ struct wmOperator *op,
+ const bool detect_udim);
+
#endif /* __ED_IMAGE_H__ */
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 5abcff436f1..12de74c6ae7 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
image_draw.c
image_edit.c
image_ops.c
+ image_sequence.c
image_undo.c
space_image.c
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index a3fa03b18b7..fe1cb1ead9e 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1207,18 +1207,6 @@ typedef struct ImageOpenData {
ImageFormatData im_format;
} ImageOpenData;
-typedef struct ImageFrameRange {
- struct ImageFrameRange *next, *prev;
- ListBase frames;
- /** The full path of the first file in the list of image files */
- char filepath[FILE_MAX];
-} ImageFrameRange;
-
-typedef struct ImageFrame {
- struct ImageFrame *next, *prev;
- int framenr;
-} ImageFrame;
-
static void image_open_init(bContext *C, wmOperator *op)
{
ImageOpenData *iod;
@@ -1233,179 +1221,18 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
op->customdata = NULL;
}
-/**
- * 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_all[out]: the list of frame numbers found in the files matching
- * the first one by name.
- */
-static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
-{
- char dir[FILE_MAXDIR];
- const bool do_frame_range = RNA_boolean_get(ptr, "use_sequence_detection");
- ImageFrameRange *frame_range = NULL;
-
- 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 */
- frame->framenr = BLI_stringdec(filename, head, tail, &digits);
-
- /* still in the same sequence */
- if (do_frame_range && (frame_range != NULL) && (STREQLEN(base_head, head, FILE_MAX)) &&
- (STREQLEN(base_tail, tail, FILE_MAX))) {
- /* pass */
- }
- else {
- /* 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);
-
- 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;
-}
-
-static int image_cmp_frame(const void *a, const void *b)
-{
- const ImageFrame *frame_a = a;
- const ImageFrame *frame_b = b;
-
- if (frame_a->framenr < frame_b->framenr) {
- return -1;
- }
- if (frame_a->framenr > frame_b->framenr) {
- return 1;
- }
- return 0;
-}
-
-/* Checks whether the given filepath refers to a UDIM texture.
- * If yes, the range from 1001 to the highest tile is returned, otherwise 0.
- *
- * If the result is positive, the filepath will be overwritten with that of
- * the 1001 tile.
- * udim_tiles may get filled even if the result ultimately is false! */
-static int image_get_udim(char *filepath, LinkNodePair *udim_tiles)
-{
- char filename[FILE_MAX], dirname[FILE_MAXDIR];
- BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
-
- unsigned short digits;
- char base_head[FILE_MAX], base_tail[FILE_MAX];
- int id = BLI_stringdec(filename, base_head, base_tail, &digits);
-
- if (id < 1001 || id >= IMA_UDIM_MAX) {
- return 0;
- }
-
- bool is_udim = true;
- bool has_primary = false;
- int max_udim = 0;
-
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(dirname, &dir);
- for (int i = 0; i < totfile; i++) {
- if (!(dir[i].type & S_IFREG)) {
- continue;
- }
- char head[FILE_MAX], tail[FILE_MAX];
- id = BLI_stringdec(dir[i].relname, head, tail, &digits);
-
- if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
- !(STREQLEN(base_tail, tail, FILE_MAX))) {
- continue;
- }
-
- if (id < 1001 || id >= IMA_UDIM_MAX) {
- is_udim = false;
- break;
- }
- if (id == 1001) {
- has_primary = true;
- }
-
- BLI_linklist_append(udim_tiles, POINTER_FROM_INT(id));
- max_udim = max_ii(max_udim, id);
- }
- BLI_filelist_free(dir, totfile);
-
- if (is_udim && has_primary) {
- char primary_filename[FILE_MAX];
- BLI_stringenc(primary_filename, base_head, base_tail, digits, 1001);
- BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
- return max_udim - 1000;
- }
- return 0;
-}
-
-/**
- * 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] offset the first frame number in the sequence.
- * \return the number of contiguous frames in the sequence
- */
-static int image_sequence_get_len(ImageFrameRange *frame_range,
- int *ofs,
- char *filepath_range,
- LinkNodePair *udim_tiles)
-{
- ImageFrame *frame;
-
- BLI_listbase_sort(&frame_range->frames, image_cmp_frame);
- BLI_strncpy(filepath_range, frame_range->filepath, FILE_MAX);
-
- frame = frame_range->frames.first;
- if (frame != NULL) {
- int frame_curr = frame->framenr;
- (*ofs) = frame_curr;
-
- if (udim_tiles != NULL) {
- int len_udim = image_get_udim(filepath_range, udim_tiles);
- if (len_udim > 0) {
- *ofs = 1001;
- return len_udim;
- }
- }
-
- while (frame != NULL && (frame->framenr == frame_curr)) {
- frame_curr++;
- frame = frame->next;
- }
- return frame_curr - (*ofs);
- }
- *ofs = 0;
- return 0;
-}
-
static Image *image_open_single(Main *bmain,
wmOperator *op,
- const char *filepath,
+ ImageFrameRange *range,
const char *relbase,
bool is_relative_path,
- bool use_multiview,
- int frame_seq_len,
- int frame_seq_ofs,
- LinkNodePair *udim_tiles)
+ bool use_multiview)
{
bool exists = false;
Image *ima = NULL;
errno = 0;
- ima = BKE_image_load_exists_ex(bmain, filepath, &exists);
+ ima = BKE_image_load_exists_ex(bmain, range->filepath, &exists);
if (!ima) {
if (op->customdata) {
@@ -1414,7 +1241,7 @@ static Image *image_open_single(Main *bmain,
BKE_reportf(op->reports,
RPT_ERROR,
"Cannot read '%s': %s",
- filepath,
+ range->filepath,
errno ? strerror(errno) : TIP_("unsupported image format"));
return NULL;
}
@@ -1439,11 +1266,11 @@ static Image *image_open_single(Main *bmain,
BKE_image_free_views(ima);
}
- if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
- if (udim_tiles && frame_seq_ofs == 1001) {
+ if ((range->length > 1) && (ima->source == IMA_SRC_FILE)) {
+ if (range->udim_tiles.first && range->offset == 1001) {
ima->source = IMA_SRC_TILED;
- for (LinkNode *node = udim_tiles->list; node; node = node->next) {
- BKE_image_add_tile(ima, POINTER_AS_INT(node->link), NULL);
+ for (LinkData *node = range->udim_tiles.first; node; node = node->next) {
+ BKE_image_add_tile(ima, POINTER_AS_INT(node->data), NULL);
}
}
else {
@@ -1464,7 +1291,6 @@ static int image_open_exec(bContext *C, wmOperator *op)
ImageUser *iuser = NULL;
ImageOpenData *iod = op->customdata;
Image *ima = NULL;
- char filepath[FILE_MAX];
int frame_seq_len = 0;
int frame_ofs = 1;
@@ -1476,83 +1302,21 @@ static int image_open_exec(bContext *C, wmOperator *op)
image_open_init(C, op);
}
- RNA_string_get(op->ptr, "filepath", filepath);
-
- 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;
-
- LinkNodePair udim_tiles = {NULL};
- LinkNodePair *udim_tiles_ptr = use_udim ? (&udim_tiles) : NULL;
-
- char filepath_range[FILE_MAX];
- int frame_range_seq_len = image_sequence_get_len(
- frame_range, &frame_range_ofs, filepath_range, udim_tiles_ptr);
- BLI_freelistN(&frame_range->frames);
-
- if (was_relative) {
- BLI_path_rel(filepath_range, BKE_main_blendfile_path(bmain));
- }
-
- Image *ima_range = image_open_single(bmain,
- op,
- filepath_range,
- BKE_main_blendfile_path(bmain),
- is_relative_path,
- use_multiview,
- frame_range_seq_len,
- frame_range_ofs,
- udim_tiles_ptr);
-
- /* take the first image */
- if ((ima == NULL) && ima_range) {
- ima = ima_range;
- frame_seq_len = frame_range_seq_len;
- frame_ofs = frame_range_ofs;
- }
+ ListBase ranges = ED_image_filesel_detect_sequences(bmain, op, use_udim);
+ for (ImageFrameRange *range = ranges.first; range; range = range->next) {
+ Image *ima_range = image_open_single(
+ bmain, op, range, BKE_main_blendfile_path(bmain), is_relative_path, use_multiview);
- BLI_linklist_free(udim_tiles.list, NULL);
+ /* take the first image */
+ if ((ima == NULL) && ima_range) {
+ ima = ima_range;
+ frame_seq_len = range->length;
+ frame_ofs = range->offset;
}
- BLI_freelistN(&frame_ranges_all);
- }
- else {
- /* for drag & drop etc. */
-
- LinkNodePair udim_tiles = {NULL};
- frame_seq_len = 1;
- char filepath_range[FILE_MAX];
- BLI_strncpy(filepath_range, filepath, FILE_MAX);
-
- if (use_udim > 0) {
- /* Try to find UDIM tiles corresponding to the image */
- int udim_len = image_get_udim(filepath_range, &udim_tiles);
-
- /* If we found something, mark the image as tiled. */
- if (udim_len) {
- frame_seq_len = udim_len;
- frame_ofs = 1001;
- }
- }
-
- ima = image_open_single(bmain,
- op,
- filepath_range,
- BKE_main_blendfile_path(bmain),
- is_relative_path,
- use_multiview,
- frame_seq_len,
- frame_ofs,
- &udim_tiles);
- BLI_linklist_free(udim_tiles.list, NULL);
+ BLI_freelistN(&range->udim_tiles);
}
+ BLI_freelistN(&ranges);
if (ima == NULL) {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
new file mode 100644
index 00000000000..09e717621d8
--- /dev/null
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -0,0 +1,249 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spimage
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_image_types.h"
+#include "DNA_space_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_access.h"
+
+#include "BKE_image.h"
+#include "BKE_main.h"
+
+#include "ED_image.h"
+
+#include "WM_types.h"
+
+typedef struct ImageFrame {
+ struct ImageFrame *next, *prev;
+ int framenr;
+} ImageFrame;
+
+/**
+ * Get a list of frames from the list of image files matching the first file
+ * name sequence pattern. The files and directory are read from standard
+ * fileselect operator properties.
+ *
+ * The output is a list of frame ranges, each containg a list of frames with
+ * matching names.
+ */
+static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges)
+{
+ char dir[FILE_MAXDIR];
+ const bool do_frame_range = RNA_boolean_get(op->ptr, "use_sequence_detection");
+ ImageFrameRange *range = NULL;
+
+ RNA_string_get(op->ptr, "directory", dir);
+ RNA_BEGIN (op->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 */
+ frame->framenr = BLI_stringdec(filename, head, tail, &digits);
+
+ /* still in the same sequence */
+ if (do_frame_range && (range != NULL) && (STREQLEN(base_head, head, FILE_MAX)) &&
+ (STREQLEN(base_tail, tail, FILE_MAX))) {
+ /* pass */
+ }
+ else {
+ /* start a new frame range */
+ range = MEM_callocN(sizeof(*range), __func__);
+ BLI_join_dirfile(range->filepath, sizeof(range->filepath), dir, filename);
+ BLI_addtail(ranges, range);
+
+ BLI_strncpy(base_head, head, sizeof(base_head));
+ BLI_strncpy(base_tail, tail, sizeof(base_tail));
+ }
+
+ BLI_addtail(&range->frames, frame);
+ MEM_freeN(filename);
+ }
+ RNA_END;
+}
+
+static int image_cmp_frame(const void *a, const void *b)
+{
+ const ImageFrame *frame_a = a;
+ const ImageFrame *frame_b = b;
+
+ if (frame_a->framenr < frame_b->framenr) {
+ return -1;
+ }
+ if (frame_a->framenr > frame_b->framenr) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Checks whether the given filepath refers to a UDIM texture.
+ * If yes, the range from 1001 to the highest tile is returned, otherwise 0.
+ *
+ * If the result is positive, the filepath will be overwritten with that of
+ * the 1001 tile.
+ *
+ * udim_tiles may get filled even if the result ultimately is false!
+ */
+static int image_get_udim(char *filepath, ListBase *udim_tiles)
+{
+ char filename[FILE_MAX], dirname[FILE_MAXDIR];
+ BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
+
+ unsigned short digits;
+ char base_head[FILE_MAX], base_tail[FILE_MAX];
+ int id = BLI_stringdec(filename, base_head, base_tail, &digits);
+
+ if (id < 1001 || id >= IMA_UDIM_MAX) {
+ return 0;
+ }
+
+ bool is_udim = true;
+ bool has_primary = false;
+ int max_udim = 0;
+
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(dirname, &dir);
+ for (int i = 0; i < totfile; i++) {
+ if (!(dir[i].type & S_IFREG)) {
+ continue;
+ }
+ char head[FILE_MAX], tail[FILE_MAX];
+ id = BLI_stringdec(dir[i].relname, head, tail, &digits);
+
+ if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
+ !(STREQLEN(base_tail, tail, FILE_MAX))) {
+ continue;
+ }
+
+ if (id < 1001 || id >= IMA_UDIM_MAX) {
+ is_udim = false;
+ break;
+ }
+ if (id == 1001) {
+ has_primary = true;
+ }
+
+ BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id)));
+ max_udim = max_ii(max_udim, id);
+ }
+ BLI_filelist_free(dir, totfile);
+
+ if (is_udim && has_primary) {
+ char primary_filename[FILE_MAX];
+ BLI_stringenc(primary_filename, base_head, base_tail, digits, 1001);
+ BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
+ return max_udim - 1000;
+ }
+ return 0;
+}
+
+/**
+ * From a list of frames, compute the start (offset) and length of the sequence
+ * of contiguous frames. If UDIM is detect, it will return UDIM tiles as well.
+ */
+static void image_detect_frame_range(ImageFrameRange *range, const bool detect_udim)
+{
+ /* UDIM */
+ if (detect_udim) {
+ int len_udim = image_get_udim(range->filepath, &range->udim_tiles);
+
+ if (len_udim > 0) {
+ range->offset = 1001;
+ range->length = len_udim;
+ return;
+ }
+ }
+
+ /* Image Sequence */
+ BLI_listbase_sort(&range->frames, image_cmp_frame);
+
+ ImageFrame *frame = range->frames.first;
+ if (frame != NULL) {
+ int frame_curr = frame->framenr;
+ range->offset = frame_curr;
+
+ while (frame != NULL && (frame->framenr == frame_curr)) {
+ frame_curr++;
+ frame = frame->next;
+ }
+
+ range->length = frame_curr - range->offset;
+ }
+ else {
+ range->length = 1;
+ range->offset = 0;
+ }
+}
+
+/* Used for both images and volume file loading. */
+ListBase ED_image_filesel_detect_sequences(Main *bmain, wmOperator *op, const bool detect_udim)
+{
+ ListBase ranges;
+ BLI_listbase_clear(&ranges);
+
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ /* File browser. */
+ if (RNA_struct_property_is_set(op->ptr, "directory") &&
+ RNA_struct_property_is_set(op->ptr, "files")) {
+ const bool was_relative = BLI_path_is_rel(filepath);
+
+ image_sequence_get_frame_ranges(op, &ranges);
+ for (ImageFrameRange *range = ranges.first; range; range = range->next) {
+ image_detect_frame_range(range, detect_udim);
+ BLI_freelistN(&range->frames);
+
+ if (was_relative) {
+ BLI_path_rel(range->filepath, BKE_main_blendfile_path(bmain));
+ }
+ }
+ }
+ /* Filepath property for drag & drop etc. */
+ else {
+ ImageFrameRange *range = MEM_callocN(sizeof(*range), __func__);
+ BLI_addtail(&ranges, range);
+
+ BLI_strncpy(range->filepath, filepath, FILE_MAX);
+ image_detect_frame_range(range, detect_udim);
+ }
+
+ return ranges;
+}