[Bf-blender-cvs] [a1598d6835d] master: UDIM: Improve tile format detection in filenames

Jesse Yurkovich noreply at git.blender.org
Thu Mar 24 05:04:18 CET 2022


Commit: a1598d6835d0c579579881bca900f9259b26d11a
Author: Jesse Yurkovich
Date:   Wed Mar 23 21:01:36 2022 -0700
Branches: master
https://developer.blender.org/rBa1598d6835d0c579579881bca900f9259b26d11a

UDIM: Improve tile format detection in filenames

There are some filenames where the UDIM pattern guessing would fail
unnecessarily. The user can fix these up afterwards but it would be
nicer if they would detect properly in the first place.

Examples:
`test.1001.ver0023.png` would guess wrong since it uses the image
sequence detection code which finds the first sequence from the end. It
would guess `filename.1001.ver<UDIM>.png`

`uv-test.u1_v2.png` would fail detection due to a bug in the processing.

Make this much more reliable and add tests for the most important tile
related get/set/detection functions.

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

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

M	source/blender/blenkernel/CMakeLists.txt
M	source/blender/blenkernel/intern/image.cc
A	source/blender/blenkernel/intern/image_test.cc

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

diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 3b5272aa600..268239ed7b5 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -818,6 +818,7 @@ if(WITH_GTESTS)
     intern/cryptomatte_test.cc
     intern/curves_geometry_test.cc
     intern/fcurve_test.cc
+    intern/image_test.cc
     intern/idprop_serialize_test.cc
     intern/image_partial_update_test.cc
     intern/lattice_deform_test.cc
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index cfdd048495d..0e3c913189c 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -9,6 +9,7 @@
 #include <cmath>
 #include <cstdio>
 #include <cstring>
+#include <ctime>
 #include <fcntl.h>
 #ifndef WIN32
 #  include <unistd.h>
@@ -16,7 +17,8 @@
 #  include <io.h>
 #endif
 
-#include <ctime>
+#include <regex>
+#include <string>
 
 #include "BLI_array.hh"
 
@@ -3316,69 +3318,24 @@ void BKE_image_ensure_tile_token(char *filename)
     return;
   }
 
-  /* Is there a sequence of digits in the filename? */
-  ushort digits;
-  char head[FILE_MAX], tail[FILE_MAX];
-  BLI_path_sequence_decode(filename, head, tail, &digits);
-  if (digits == 4) {
-    sprintf(filename, "%s<UDIM>%s", head, tail);
-    return;
-  }
-
-  /* Is there a sequence like u##_v#### in the filename? */
-  uint cur = 0;
-  uint name_end = strlen(filename);
-  uint u_digits = 0;
-  uint v_digits = 0;
-  uint u_start = (uint)-1;
-  bool u_found = false;
-  bool v_found = false;
-  bool sep_found = false;
-  while (cur < name_end) {
-    if (filename[cur] == 'u') {
-      u_found = true;
-      u_digits = 0;
-      u_start = cur;
-    }
-    else if (filename[cur] == 'v') {
-      v_found = true;
-      v_digits = 0;
-    }
-    else if (u_found && !v_found) {
-      if (isdigit(filename[cur]) && u_digits < 2) {
-        u_digits++;
-      }
-      else if (filename[cur] == '_') {
-        sep_found = true;
-      }
-      else {
-        u_found = false;
-      }
-    }
-    else if (u_found && u_digits > 0 && v_found) {
-      if (isdigit(filename[cur])) {
-        if (v_digits < 4) {
-          v_digits++;
-        }
-        else {
-          u_found = false;
-          v_found = false;
-        }
-      }
-      else if (v_digits > 0) {
-        break;
-      }
-    }
+  std::string path(filename);
+  std::smatch match;
 
-    cur++;
+  /* General 4-digit "udim" pattern. As this format is susceptible to ambiguity
+   * with other digit sequences, we can leverage the supported range of roughly
+   * 1000 through 2000 to provide better detection.
+   */
+  std::regex pattern("(^|.*?\\D)([12]\\d{3})(\\D.*)");
+  if (std::regex_search(path, match, pattern)) {
+    BLI_strncpy(filename, match.format("$1<UDIM>$3").c_str(), FILE_MAX);
+    return;
   }
 
-  if (u_found && sep_found && v_found && (u_digits + v_digits > 1)) {
-    const char *token = "<UVTILE>";
-    const size_t token_length = strlen(token);
-    memmove(filename + u_start + token_length, filename + cur, name_end - cur);
-    memcpy(filename + u_start, token, token_length);
-    filename[u_start + token_length + (name_end - cur)] = '\0';
+  /* General u##_v### "uvtile" pattern. */
+  pattern = std::regex("(.*)(u\\d{1,2}_v\\d{1,3})(\\D.*)");
+  if (std::regex_search(path, match, pattern)) {
+    BLI_strncpy(filename, match.format("$1<UVTILE>$3").c_str(), FILE_MAX);
+    return;
   }
 }
 
diff --git a/source/blender/blenkernel/intern/image_test.cc b/source/blender/blenkernel/intern/image_test.cc
new file mode 100644
index 00000000000..9c15fc62d21
--- /dev/null
+++ b/source/blender/blenkernel/intern/image_test.cc
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. */
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "BKE_image.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "testing/testing.h"
+
+namespace blender::bke::tests {
+
+TEST(udim, image_ensure_tile_token)
+{
+  auto verify = [](const char *original, const char *expected) {
+    char result[FILE_MAX];
+
+    BLI_strncpy(result, original, sizeof(result));
+    BKE_image_ensure_tile_token(result);
+    EXPECT_STREQ(result, expected);
+  };
+
+  /* Already present tokens. */
+  verify("test.<UDIM>.png", "test.<UDIM>.png");
+  verify("test.<UVTILE>.png", "test.<UVTILE>.png");
+
+  /* UDIM pattern detection. */
+  verify("test.1002.png", "test.<UDIM>.png");
+  verify("test-1002-ao.png", "test-<UDIM>-ao.png");
+  verify("test_1002_ao.png", "test_<UDIM>_ao.png");
+  verify("test.1002.ver0023.png", "test.<UDIM>.ver0023.png");
+  verify("test.ver0023.1002.png", "test.ver0023.<UDIM>.png");
+  verify("1002test.png", "<UDIM>test.png");
+  verify("test1002.png", "test<UDIM>.png");
+
+  /* UVTILE pattern detection. */
+  verify("uv-test.u2_v10.png", "uv-test.<UVTILE>.png");
+  verify("uv-test-u2_v10-ao.png", "uv-test-<UVTILE>-ao.png");
+  verify("uv-test_u2_v10_ao.png", "uv-test_<UVTILE>_ao.png");
+  verify("uv-test.u10_v100.png", "uv-test.<UVTILE>.png");
+  verify("u_v-test.u2_v10.png", "u_v-test.<UVTILE>.png");
+  verify("u2_v10uv-test.png", "<UVTILE>uv-test.png");
+  verify("u2_v10u_v-test.png", "<UVTILE>u_v-test.png");
+
+  /* Incorrect patterns. */
+  for (const char *incorrect : {"test.123.png",
+                                "test.12345.png",
+                                "test.uv.png",
+                                "test.u1v.png",
+                                "test.uv1.png",
+                                "test.u_v.png",
+                                "test.u1_v.png",
+                                "test.u_v2.png",
+                                "test.u2v3.png",
+                                "test.u123_v1.png",
+                                "test.u1_v12345.png"}) {
+    /* These should not result in modifications happening. */
+    verify(incorrect, incorrect);
+  }
+}
+
+TEST(udim, image_get_tile_strformat)
+{
+  eUDIM_TILE_FORMAT tile_format;
+  char *udim_pattern;
+
+  /* Parameter validation. */
+  udim_pattern = BKE_image_get_tile_strformat(nullptr, &tile_format);
+  EXPECT_EQ(udim_pattern, nullptr);
+
+  udim_pattern = BKE_image_get_tile_strformat("", nullptr);
+  EXPECT_EQ(udim_pattern, nullptr);
+
+  /* Typical usage. */
+  udim_pattern = BKE_image_get_tile_strformat("", &tile_format);
+  EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_NONE);
+  EXPECT_EQ(udim_pattern, nullptr);
+
+  udim_pattern = BKE_image_get_tile_strformat("test.<UNKNOWN>.png", &tile_format);
+  EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_NONE);
+  EXPECT_EQ(udim_pattern, nullptr);
+
+  udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format);
+  EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM);
+  EXPECT_STREQ(udim_pattern, "test.%d.png");
+  MEM_freeN(udim_pattern);
+
+  udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format);
+  EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UVTILE);
+  EXPECT_STREQ(udim_pattern, "test.u%d_v%d.png");
+  MEM_freeN(udim_pattern);
+}
+
+TEST(udim, image_get_tile_number_from_filepath)
+{
+  eUDIM_TILE_FORMAT tile_format;
+  char *udim_pattern;
+  int tile_number;
+
+  udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format);
+  EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM);
+  EXPECT_NE(udim_pattern, nullptr);
+
+  /* Parameter validation. */
+  EXPECT_FALSE(
+      BKE_image_get_tile_number_from_filepath(nullptr, udim_pattern, tile_format, &tile_number));
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "test.1004.png", nullptr, tile_format, &tile_number));
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "test.1004.png", udim_pattern, UDIM_TILE_FORMAT_NONE, &tile_number));
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "test.1004.png", udim_pattern, tile_format, nullptr));
+
+  /* UDIM tile format tests. */
+  EXPECT_TRUE(BKE_image_get_tile_number_from_filepath(
+      "test.1004.png", udim_pattern, tile_format, &tile_number));
+  EXPECT_EQ(tile_number, 1004);
+
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "has_no_number.png", udim_pattern, tile_format, &tile_number));
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "test.X.png", udim_pattern, tile_format, &tile_number));
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "wrong.1004.png", udim_pattern, tile_format, &tile_number));
+
+  MEM_freeN(udim_pattern);
+
+  /* UVTILE tile format tests. */
+  udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format);
+  EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UVTILE);
+  EXPECT_NE(udim_pattern, nullptr);
+
+  EXPECT_TRUE(BKE_image_get_tile_number_from_filepath(
+      "test.u2_v2.png", udim_pattern, tile_format, &tile_number));
+  EXPECT_EQ(tile_number, 1012);
+
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "has_no_number.png", udim_pattern, tile_format, &tile_number));
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "test.u1_vX.png", udim_pattern, tile_format, &tile_number));
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "test.uX_v1.png", udim_pattern, tile_format, &tile_number));
+  EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+      "wrong.u2_v2.png", udim_pattern, tile_format, &tile_number));
+
+  MEM_freeN(udim_pattern);
+}
+
+TEST(udim, image_set_filepath_from_tile_number)
+{
+  eUDIM_TILE_FORMAT tile_format;
+  char *udim_pattern;
+
+  udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format);
+  EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM);
+  EXPECT_NE(udim_pattern, nullptr);
+
+  char filepath[FILE_MAX];
+
+  /* Parameter validation. */
+  BLI_strncpy(filepath, "xxxx", FILE_MAX);
+
+  BKE_image_set_filepath_from_tile_number(nullptr, udim_pattern, tile_format, 1028);
+  BKE_image_set_filepath_from_tile_number(filepath, nullptr, tile_format, 1028);
+  EXPECT_STREQ(filepath, "xxxx");
+  BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, UDIM_TILE_FORMAT_NONE, 1028);
+  EXPECT_STREQ(filepath, "xxxx");
+
+  /* UDIM tile format tests. */
+  BKE_image_set_filepath_from_tile_number(f

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list