|
6 | 6 | from pywuffs.aux import * |
7 | 7 | from pywuffs import * |
8 | 8 |
|
9 | | -IMAGES_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "images/") |
| 9 | +IMAGES_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "images") |
10 | 10 | TEST_IMAGES = [ |
11 | | - (ImageDecoderType.PNG, IMAGES_PATH + "/lena.png"), |
12 | | - (ImageDecoderType.BMP, IMAGES_PATH + "/lena.bmp"), |
13 | | - (ImageDecoderType.TGA, IMAGES_PATH + "/lena.tga"), |
14 | | - (ImageDecoderType.NIE, IMAGES_PATH + "/hippopotamus.nie"), |
15 | | - (ImageDecoderType.GIF, IMAGES_PATH + "/lena.gif"), |
16 | | - (ImageDecoderType.WBMP, IMAGES_PATH + "/lena.wbmp"), |
17 | | - (ImageDecoderType.JPEG, IMAGES_PATH + "/lena.jpeg"), |
18 | | - (ImageDecoderType.WEBP, IMAGES_PATH + "/lena.webp"), |
19 | | - (ImageDecoderType.QOI, IMAGES_PATH + "/lena.qoi"), |
20 | | - (ImageDecoderType.ETC2, IMAGES_PATH + "/bricks-color.etc2.pkm"), |
21 | | - (ImageDecoderType.TH, IMAGES_PATH + "/1QcSHQRnh493V4dIh4eXh1h4kJUI.th") |
| 11 | + (ImageDecoderType.PNG, os.path.join(IMAGES_PATH, "lena.png")), |
| 12 | + (ImageDecoderType.BMP, os.path.join(IMAGES_PATH, "lena.bmp")), |
| 13 | + (ImageDecoderType.TGA, os.path.join(IMAGES_PATH, "lena.tga")), |
| 14 | + (ImageDecoderType.NIE, os.path.join(IMAGES_PATH, "hippopotamus.nie")), |
| 15 | + (ImageDecoderType.GIF, os.path.join(IMAGES_PATH, "lena.gif")), |
| 16 | + (ImageDecoderType.WBMP, os.path.join(IMAGES_PATH, "lena.wbmp")), |
| 17 | + (ImageDecoderType.JPEG, os.path.join(IMAGES_PATH, "lena.jpeg")), |
| 18 | + (ImageDecoderType.WEBP, os.path.join(IMAGES_PATH, "lena.webp")), |
| 19 | + (ImageDecoderType.QOI, os.path.join(IMAGES_PATH, "lena.qoi")), |
| 20 | + (ImageDecoderType.ETC2, os.path.join(IMAGES_PATH, "bricks-color.etc2.pkm")), |
| 21 | + (ImageDecoderType.TH, os.path.join(IMAGES_PATH, "1QcSHQRnh493V4dIh4eXh1h4kJUI.th")) |
22 | 22 | ] |
| 23 | +EXIF_FOURCC = 0x45584946 |
23 | 24 |
|
24 | 25 |
|
25 | 26 | # Positive test cases |
@@ -48,7 +49,7 @@ def test_decode_image_with_metadata(param): |
48 | 49 | config = ImageDecoderConfig() |
49 | 50 | config.flags = param[0] |
50 | 51 | decoder = ImageDecoder(config) |
51 | | - decoding_result = decoder.decode(IMAGES_PATH + "/lena_exif.png") |
| 52 | + decoding_result = decoder.decode(os.path.join(IMAGES_PATH, "lena_exif.png")) |
52 | 53 | assert_decoded(decoding_result, param[1]) |
53 | 54 |
|
54 | 55 |
|
@@ -140,12 +141,12 @@ def test_decode_image_quirks_quality(): |
140 | 141 | config = ImageDecoderConfig() |
141 | 142 | config.quirks = {ImageDecoderQuirks.QUALITY: LowerQuality} |
142 | 143 | decoder = ImageDecoder(config) |
143 | | - decoding_result_lower_quality = decoder.decode(IMAGES_PATH + "/lena.jpeg") |
| 144 | + decoding_result_lower_quality = decoder.decode(os.path.join(IMAGES_PATH, "lena.jpeg")) |
144 | 145 | assert_decoded(decoding_result_lower_quality) |
145 | 146 | assert decoding_result_lower_quality.pixbuf.shape == (32, 32, 4) |
146 | 147 | config.quirks = {ImageDecoderQuirks.QUALITY: HigherQuality} |
147 | 148 | decoder = ImageDecoder(config) |
148 | | - decoding_result_higher_quality = decoder.decode(IMAGES_PATH + "/lena.jpeg") |
| 149 | + decoding_result_higher_quality = decoder.decode(os.path.join(IMAGES_PATH, "lena.jpeg")) |
149 | 150 | assert_decoded(decoding_result_higher_quality) |
150 | 151 | assert decoding_result_higher_quality.pixbuf.shape == (32, 32, 4) |
151 | 152 | assert decoding_result_lower_quality != decoding_result_higher_quality |
@@ -176,12 +177,12 @@ def test_decode_image_exif_metadata(): |
176 | 177 | config = ImageDecoderConfig() |
177 | 178 | config.flags = [ImageDecoderFlags.REPORT_METADATA_EXIF] |
178 | 179 | decoder = ImageDecoder(config) |
179 | | - decoding_result = decoder.decode(IMAGES_PATH + "/lena_exif.png") |
| 180 | + decoding_result = decoder.decode(os.path.join(IMAGES_PATH, "lena_exif.png")) |
180 | 181 | assert_decoded(decoding_result, 1) |
181 | 182 | assert decoding_result.pixbuf.shape == (32, 32, 4) |
182 | 183 | meta_minfo = decoding_result.reported_metadata[0].minfo |
183 | 184 | meta_bytes = decoding_result.reported_metadata[0].data.tobytes() |
184 | | - assert meta_minfo.metadata__fourcc() == 1163413830 # EXIF |
| 185 | + assert meta_minfo.metadata__fourcc() == EXIF_FOURCC |
185 | 186 | assert meta_bytes[:2] == b"II" # little endian |
186 | 187 | exif_orientation = 0 |
187 | 188 | cursor = 0 |
@@ -215,7 +216,7 @@ def test_decode_image_invalid_kvp_chunk(): |
215 | 216 | config = ImageDecoderConfig() |
216 | 217 | config.flags = [ImageDecoderFlags.REPORT_METADATA_KVP] |
217 | 218 | decoder = ImageDecoder(config) |
218 | | - decoding_result = decoder.decode(IMAGES_PATH + "/lena.png") |
| 219 | + decoding_result = decoder.decode(os.path.join(IMAGES_PATH, "lena.png")) |
219 | 220 | assert_not_decoded(decoding_result, "png: bad text chunk (not Latin-1)", 1) |
220 | 221 |
|
221 | 222 |
|
@@ -284,5 +285,53 @@ def test_decode_image_max_incl_metadata_length(): |
284 | 285 | config.max_incl_metadata_length = 8 |
285 | 286 | config.flags = [ImageDecoderFlags.REPORT_METADATA_EXIF] |
286 | 287 | decoder = ImageDecoder(config) |
287 | | - decoding_result = decoder.decode(IMAGES_PATH + "/lena_exif.png") |
| 288 | + decoding_result = decoder.decode(os.path.join(IMAGES_PATH, "lena_exif.png")) |
288 | 289 | assert_not_decoded(decoding_result, ImageDecoderError.MaxInclMetadataLengthExceeded) |
| 290 | + |
| 291 | + |
| 292 | +# Multithreading tests |
| 293 | + |
| 294 | +from concurrent.futures import ThreadPoolExecutor |
| 295 | + |
| 296 | + |
| 297 | +def test_decode_multithreaded(): |
| 298 | + config = ImageDecoderConfig() |
| 299 | + |
| 300 | + def decode(image): |
| 301 | + decoder = ImageDecoder(config) |
| 302 | + return decoder.decode(image) |
| 303 | + |
| 304 | + test_image = os.path.join(IMAGES_PATH, "lena.png") |
| 305 | + with open(test_image, "rb") as f: |
| 306 | + test_image_data = f.read() |
| 307 | + |
| 308 | + for payload in (test_image, test_image_data): |
| 309 | + for num_threads in (1, 2, 4, 8): |
| 310 | + with ThreadPoolExecutor(max_workers=num_threads) as executor: |
| 311 | + futures = [executor.submit(decode, payload) for _ in range(num_threads)] |
| 312 | + results = [future.result() for future in futures] |
| 313 | + for result in results: |
| 314 | + assert_decoded(result) |
| 315 | + assert np.array_equal(results[0].pixbuf, result.pixbuf) |
| 316 | + |
| 317 | + |
| 318 | +def test_decode_multithreaded_with_metadata(): |
| 319 | + config = ImageDecoderConfig() |
| 320 | + config.flags = [ImageDecoderFlags.REPORT_METADATA_EXIF] |
| 321 | + |
| 322 | + def decode(image): |
| 323 | + decoder = ImageDecoder(config) |
| 324 | + return decoder.decode(image) |
| 325 | + |
| 326 | + test_image = os.path.join(IMAGES_PATH, "lena_exif.png") |
| 327 | + num_threads = 4 |
| 328 | + |
| 329 | + with ThreadPoolExecutor(max_workers=num_threads) as executor: |
| 330 | + futures = [executor.submit(decode, test_image) for _ in range(num_threads)] |
| 331 | + results = [future.result() for future in futures] |
| 332 | + for result in results: |
| 333 | + assert_decoded(result, 1) |
| 334 | + meta_minfo = result.reported_metadata[0].minfo |
| 335 | + meta_bytes = result.reported_metadata[0].data.tobytes() |
| 336 | + assert meta_minfo.metadata__fourcc() == EXIF_FOURCC |
| 337 | + assert meta_bytes[:2] == b"II" |
0 commit comments