diff options
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image.cc | 79 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/image_test.cc | 186 |
3 files changed, 205 insertions, 61 deletions
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(filepath, udim_pattern, tile_format, 1028); + EXPECT_STREQ(filepath, "test.1028.png"); + 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); + + BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, 1028); + EXPECT_STREQ(filepath, "test.u8_v3.png"); + MEM_freeN(udim_pattern); +} + +} // namespace blender::bke::tests |