Blender V5.0
source/blender/blenkernel/intern/image_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_listbase.h"
6#include "BLI_path_utils.hh"
7#include "BLI_string.h"
8#include "BLI_string_ref.hh"
9#include "BLI_vector.hh"
10
11#include "BKE_appdir.hh"
12#include "BKE_global.hh"
13#include "BKE_idtype.hh"
14#include "BKE_image.hh"
15#include "BKE_main.hh"
16
17#include "MEM_guardedalloc.h"
18
19#include "testing/testing.h"
20#include "gmock/gmock.h"
21
22#include "IMB_imbuf.hh"
23#include "IMB_moviecache.hh"
24
25#include "DNA_image_types.h"
26
27#include "RE_pipeline.h"
28
29#include "CLG_log.h"
30
31namespace blender::bke::tests {
32
33using testing::Eq;
34using testing::Pointwise;
35
36TEST(udim, image_ensure_tile_token)
37{
38 auto verify = [](const char *original, const char *expected) {
39 char result[FILE_MAX];
40
41 STRNCPY(result, original);
43 EXPECT_STREQ(result, expected);
44 };
45
46 /* Already present tokens. */
47 verify("test.<UDIM>.png", "test.<UDIM>.png");
48 verify("test.<UVTILE>.png", "test.<UVTILE>.png");
49
50 /* UDIM pattern detection. */
51 verify("test.1002.png", "test.<UDIM>.png");
52 verify("test-1002-ao.png", "test-<UDIM>-ao.png");
53 verify("test_1002_ao.png", "test_<UDIM>_ao.png");
54 verify("test.1002.ver0023.png", "test.<UDIM>.ver0023.png");
55 verify("test.ver0023.1002.png", "test.ver0023.<UDIM>.png");
56 verify("test.1002.1.png", "test.<UDIM>.1.png");
57 verify("test.1.1002.png", "test.1.<UDIM>.png");
58 verify("test-2022-01-01.1002.png", "test-2022-01-01.<UDIM>.png");
59 verify("1111_11.1002.png", "1111_11.<UDIM>.png");
60 verify("2111_01.1002.png", "2111_01.<UDIM>.png");
61 verify("2022_1002_100200.1002.png", "2022_1002_100200.<UDIM>.png");
62
63 /* UVTILE pattern detection. */
64 verify("uv-test.u2_v10.png", "uv-test.<UVTILE>.png");
65 verify("uv-test-u2_v10-ao.png", "uv-test-<UVTILE>-ao.png");
66 verify("uv-test_u2_v10_ao.png", "uv-test_<UVTILE>_ao.png");
67 verify("uv-test.u10_v100.png", "uv-test.<UVTILE>.png");
68 verify("u_v-test.u2_v10.png", "u_v-test.<UVTILE>.png");
69 verify("u2_v10uv-test.png", "<UVTILE>uv-test.png");
70 verify("u2_v10u_v-test.png", "<UVTILE>u_v-test.png");
71
72 /* Patterns which should not be detected as UDIMs. */
73 for (const char *incorrect : {"1002.png",
74 "1002test.png",
75 "test1002.png",
76 "test(1002).png",
77 "(1002)test.png",
78 "test-1080p.png",
79 "test-1920x1080.png",
80 "test.123.png",
81 "test.12345.png",
82 "test.uv.png",
83 "test.u1v.png",
84 "test.uv1.png",
85 "test.u_v.png",
86 "test.u1_v.png",
87 "test.u_v2.png",
88 "test.u2v3.png",
89 "test.u123_v1.png",
90 "test.u1_v12345.png"})
91 {
92 /* These should not result in modifications happening. */
93 verify(incorrect, incorrect);
94 }
95}
96
97TEST(udim, image_get_tile_strformat)
98{
99 eUDIM_TILE_FORMAT tile_format;
100 char *udim_pattern;
101
102 /* Parameter validation. */
103 udim_pattern = BKE_image_get_tile_strformat(nullptr, &tile_format);
104 EXPECT_EQ(udim_pattern, nullptr);
105
106 udim_pattern = BKE_image_get_tile_strformat("", nullptr);
107 EXPECT_EQ(udim_pattern, nullptr);
108
109 /* Typical usage. */
110 udim_pattern = BKE_image_get_tile_strformat("", &tile_format);
111 EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_NONE);
112 EXPECT_EQ(udim_pattern, nullptr);
113
114 udim_pattern = BKE_image_get_tile_strformat("test.<UNKNOWN>.png", &tile_format);
115 EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_NONE);
116 EXPECT_EQ(udim_pattern, nullptr);
117
118 udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format);
119 EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM);
120 EXPECT_STREQ(udim_pattern, "test.%d.png");
121 MEM_freeN(udim_pattern);
122
123 udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format);
125 EXPECT_STREQ(udim_pattern, "test.u%d_v%d.png");
126 MEM_freeN(udim_pattern);
127}
128
129TEST(udim, image_get_tile_number_from_filepath)
130{
131 eUDIM_TILE_FORMAT tile_format;
132 char *udim_pattern;
133 int tile_number;
134
135 udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format);
136 EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM);
137 EXPECT_NE(udim_pattern, nullptr);
138
139 /* Parameter validation. */
140 EXPECT_FALSE(
141 BKE_image_get_tile_number_from_filepath(nullptr, udim_pattern, tile_format, &tile_number));
143 "test.1004.png", nullptr, tile_format, &tile_number));
145 "test.1004.png", udim_pattern, UDIM_TILE_FORMAT_NONE, &tile_number));
147 "test.1004.png", udim_pattern, tile_format, nullptr));
148
149 /* UDIM tile format tests. */
151 "test.1004.png", udim_pattern, tile_format, &tile_number));
152 EXPECT_EQ(tile_number, 1004);
153
155 "has_no_number.png", udim_pattern, tile_format, &tile_number));
157 "test.X.png", udim_pattern, tile_format, &tile_number));
159 "wrong.1004.png", udim_pattern, tile_format, &tile_number));
160
161 MEM_freeN(udim_pattern);
162
163 /* UVTILE tile format tests. */
164 udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format);
166 EXPECT_NE(udim_pattern, nullptr);
167
169 "test.u2_v2.png", udim_pattern, tile_format, &tile_number));
170 EXPECT_EQ(tile_number, 1012);
171
173 "has_no_number.png", udim_pattern, tile_format, &tile_number));
175 "test.u1_vX.png", udim_pattern, tile_format, &tile_number));
177 "test.uX_v1.png", udim_pattern, tile_format, &tile_number));
179 "wrong.u2_v2.png", udim_pattern, tile_format, &tile_number));
180
181 MEM_freeN(udim_pattern);
182}
183
184TEST(udim, image_set_filepath_from_tile_number)
185{
186 eUDIM_TILE_FORMAT tile_format;
187 char *udim_pattern;
188
189 udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format);
190 EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM);
191 EXPECT_NE(udim_pattern, nullptr);
192
193 char filepath[FILE_MAX];
194
195 /* Parameter validation. */
196 STRNCPY(filepath, "xxxx");
197
198 BKE_image_set_filepath_from_tile_number(nullptr, udim_pattern, tile_format, 1028);
199 BKE_image_set_filepath_from_tile_number(filepath, nullptr, tile_format, 1028);
200 EXPECT_STREQ(filepath, "xxxx");
202 EXPECT_STREQ(filepath, "xxxx");
203
204 /* UDIM tile format tests. */
205 BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, 1028);
206 EXPECT_STREQ(filepath, "test.1028.png");
207 MEM_freeN(udim_pattern);
208
209 /* UVTILE tile format tests. */
210 udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format);
212 EXPECT_NE(udim_pattern, nullptr);
213
214 BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, 1028);
215 EXPECT_STREQ(filepath, "test.u8_v3.png");
216 MEM_freeN(udim_pattern);
217}
218
219class ImageTest : public ::testing::Test {
220 Main *bmain_ = nullptr;
221
222 RenderResult *get_image_render_result(Image &image)
223 {
224 ImageUser iuser{};
225 BKE_imageuser_default(&iuser);
226
227 ImBuf *temp_ibuf = BKE_image_acquire_ibuf(&image, &iuser, nullptr);
228 BKE_image_release_ibuf(&image, temp_ibuf, nullptr);
229
230 return image.rr;
231 }
232
233 protected:
234 static void SetUpTestSuite()
235 {
236 CLG_init();
238 }
239
240 static void TearDownTestSuite()
241 {
242 CLG_exit();
243 }
244
245 void SetUp() override
246 {
248 IMB_init();
250
251 bmain_ = BKE_main_new();
252 G_MAIN = bmain_;
253 }
254
255 void TearDown() override
256 {
257 BKE_main_free(bmain_);
258 G_MAIN = nullptr;
259
261 IMB_exit();
263 }
264
265 Image *load_image(const char *path)
266 {
267 const std::string asset_dir = blender::tests::flags_test_asset_dir();
268 return BKE_image_load(bmain_, (asset_dir + SEP_STR + "imbuf_io" + SEP_STR + path).c_str());
269 }
270
272 {
273 RenderResult *render_result = get_image_render_result(image);
274 if (!render_result) {
275 ADD_FAILURE() << "Missing image RenderResult";
276 return {};
277 }
278
279 Vector<std::string> layer_names;
280 LISTBASE_FOREACH (const RenderLayer *, layer, &render_result->layers) {
281 layer_names.append(layer->name);
282 }
283
284 return layer_names;
285 }
286
288 {
289 RenderResult *render_result = get_image_render_result(image);
290 if (!render_result) {
291 ADD_FAILURE() << "Missing image RenderResult";
292 return {};
293 }
294
295 LISTBASE_FOREACH (const RenderLayer *, layer, &render_result->layers) {
296 if (layer->name == layer_name) {
297 Vector<std::string> pass_names;
298 LISTBASE_FOREACH (const RenderPass *, pass, &layer->passes) {
299 pass_names.append(pass->name);
300 }
301 return pass_names;
302 }
303 }
304
305 return {};
306 }
307};
308
309TEST_F(ImageTest, multilayer)
310{
311 /* Multi-layer file from another DCC originally reported as #108980.
312 * The expected passes are obtained from Blender 4.2 Beta f069692caf8, with the
313 * !118867 reverted. File Scene_RenderLayer_000.exr from the report was used. */
314 {
315 Image *image = load_image("multilayer" SEP_STR "108980.exr");
316 ASSERT_NE(image, nullptr);
317
318 EXPECT_THAT(get_image_layer_names(*image), Pointwise(Eq(), {""}));
319 EXPECT_THAT(get_image_pass_names_for_layer(*image, ""),
320 Pointwise(Eq(),
321 {"Combined",
322 "Albedo",
323 "Nsx",
324 "Nsy",
325 "Nsz",
326 "Nx",
327 "Ny",
328 "Nz",
329 "Px",
330 "Py",
331 "Pz",
332 "RelativeVariance",
333 "Variance",
334 "dzdx",
335 "dzdy",
336 "u"}));
337 }
338
339 /* Multi-layer file from another DCC originally reported as #124217.
340 * The expected passes are obtained from Blender 4.2 Beta f069692caf8, with the
341 * !118867 reverted. File test.exr from the report was used. */
342 {
343 Image *image = load_image("multilayer" SEP_STR "124217.exr");
344 ASSERT_NE(image, nullptr);
345
346 EXPECT_THAT(get_image_layer_names(*image), Pointwise(Eq(), {""}));
347 EXPECT_THAT(get_image_pass_names_for_layer(*image, ""),
348 Pointwise(Eq(),
349 {"Combined",
350 "Depth",
351 "AO",
352 "ID",
353 "crypto_material",
354 "crypto_material00",
355 "crypto_material01",
356 "crypto_material02",
357 "crypto_material03",
358 "crypto_material04",
359 "crypto_material05",
360 "crypto_material06",
361 "crypto_object",
362 "crypto_object00",
363 "crypto_object01",
364 "crypto_object02",
365 "crypto_object03",
366 "crypto_object04",
367 "crypto_object05",
368 "crypto_object06",
369 "diffuse",
370 "opacity",
371 "specular",
372 "v"}));
373 }
374
375 /* Multi-part file from another DCC, originally reported as #101227.
376 * The expected passes are obtained from Blender 4.2 Beta f069692caf8, with the
377 * !118867 landed. */
378 {
379 Image *image = load_image("multilayer" SEP_STR "101227.exr");
380 ASSERT_NE(image, nullptr);
381
382 EXPECT_THAT(get_image_layer_names(*image), Pointwise(Eq(), {""}));
383 EXPECT_THAT(get_image_pass_names_for_layer(*image, ""),
384 Pointwise(Eq(), {"C", "N", "albedo", "depth"}));
385 }
386}
387
388} // namespace blender::bke::tests
void BKE_appdir_init()
Definition appdir.cc:93
void BKE_appdir_exit()
Definition appdir.cc:101
#define G_MAIN
void BKE_idtype_init()
Definition idtype.cc:121
eUDIM_TILE_FORMAT
Definition BKE_image.hh:453
@ UDIM_TILE_FORMAT_UVTILE
Definition BKE_image.hh:456
@ UDIM_TILE_FORMAT_NONE
Definition BKE_image.hh:454
@ UDIM_TILE_FORMAT_UDIM
Definition BKE_image.hh:455
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
char * BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format)
Image * BKE_image_load(Main *bmain, const char *filepath)
void BKE_image_set_filepath_from_tile_number(char *filepath, const char *pattern, eUDIM_TILE_FORMAT tile_format, int tile_number)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
bool BKE_image_get_tile_number_from_filepath(const char *filepath, const char *pattern, eUDIM_TILE_FORMAT tile_format, int *r_tile_number)
void BKE_image_ensure_tile_token_filename_only(char *filename, size_t filename_maxncpy)
void BKE_imageuser_default(ImageUser *iuser)
Main * BKE_main_new()
Definition main.cc:89
void BKE_main_free(Main *bmain)
Definition main.cc:192
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
#define LISTBASE_FOREACH(type, var, list)
#define FILE_MAX
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
void CLG_exit()
Definition clog.cc:880
void CLG_init()
Definition clog.cc:873
void IMB_exit()
Definition module.cc:21
void IMB_init()
Definition module.cc:15
void IMB_moviecache_destruct()
void IMB_moviecache_init()
Read Guarded memory(de)allocation.
void append(const T &value)
Vector< std::string > get_image_pass_names_for_layer(Image &image, StringRefNull layer_name)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
TEST_F(ArmatureDeformTest, MeshDeform)
TEST(action_groups, ReconstructGroupsWithReordering)
ListBase layers
#define SEP_STR
Definition unit.cc:39