|
2 | 2 |
|
3 | 3 | from io import BytesIO
|
4 | 4 |
|
| 5 | +import pytest |
| 6 | + |
5 | 7 | from PIL import Image, IptcImagePlugin, TiffImagePlugin, TiffTags
|
6 | 8 |
|
7 | 9 | from .helper import assert_image_equal, hopper
|
8 | 10 |
|
9 | 11 | TEST_FILE = "Tests/images/iptc.jpg"
|
10 | 12 |
|
11 | 13 |
|
| 14 | +def create_iptc_image(info: dict[str, int] = {}) -> BytesIO: |
| 15 | + def field(tag, value): |
| 16 | + return bytes((0x1C,) + tag + (0, len(value))) + value |
| 17 | + |
| 18 | + data = field((3, 60), bytes((info.get("layers", 1), info.get("component", 0)))) |
| 19 | + data += field((3, 120), bytes((info.get("compression", 1),))) |
| 20 | + if "band" in info: |
| 21 | + data += field((3, 65), bytes((info["band"] + 1,))) |
| 22 | + data += field((3, 20), b"\x01") # width |
| 23 | + data += field((3, 30), b"\x01") # height |
| 24 | + data += field( |
| 25 | + (8, 10), |
| 26 | + bytes((info.get("data", 0),)), |
| 27 | + ) |
| 28 | + |
| 29 | + return BytesIO(data) |
| 30 | + |
| 31 | + |
12 | 32 | def test_open() -> None:
|
13 | 33 | expected = Image.new("L", (1, 1))
|
14 | 34 |
|
15 |
| - f = BytesIO( |
16 |
| - b"\x1c\x03<\x00\x02\x01\x00\x1c\x03x\x00\x01\x01\x1c\x03\x14\x00\x01\x01" |
17 |
| - b"\x1c\x03\x1e\x00\x01\x01\x1c\x08\n\x00\x01\x00" |
18 |
| - ) |
| 35 | + f = create_iptc_image() |
19 | 36 | with Image.open(f) as im:
|
20 |
| - assert im.tile == [("iptc", (0, 0, 1, 1), 25, "raw")] |
| 37 | + assert im.tile == [("iptc", (0, 0, 1, 1), 25, ("raw", None))] |
21 | 38 | assert_image_equal(im, expected)
|
22 | 39 |
|
23 | 40 | with Image.open(f) as im:
|
24 | 41 | assert im.load() is not None
|
25 | 42 |
|
26 | 43 |
|
| 44 | +def test_field_length() -> None: |
| 45 | + f = create_iptc_image() |
| 46 | + f.seek(28) |
| 47 | + f.write(b"\xff") |
| 48 | + with pytest.raises(OSError, match="illegal field length in IPTC/NAA file"): |
| 49 | + with Image.open(f): |
| 50 | + pass |
| 51 | + |
| 52 | + |
| 53 | +@pytest.mark.parametrize("layers, mode", ((3, "RGB"), (4, "CMYK"))) |
| 54 | +def test_layers(layers: int, mode: str) -> None: |
| 55 | + for band in range(-1, layers): |
| 56 | + info = {"layers": layers, "component": 1, "data": 5} |
| 57 | + if band != -1: |
| 58 | + info["band"] = band |
| 59 | + f = create_iptc_image(info) |
| 60 | + with Image.open(f) as im: |
| 61 | + assert im.mode == mode |
| 62 | + |
| 63 | + data = [0] * layers |
| 64 | + data[max(band, 0)] = 5 |
| 65 | + assert im.getpixel((0, 0)) == tuple(data) |
| 66 | + |
| 67 | + |
| 68 | +def test_unknown_compression() -> None: |
| 69 | + f = create_iptc_image({"compression": 2}) |
| 70 | + with pytest.raises(OSError, match="Unknown IPTC image compression"): |
| 71 | + with Image.open(f): |
| 72 | + pass |
| 73 | + |
| 74 | + |
| 75 | +def test_getiptcinfo() -> None: |
| 76 | + f = create_iptc_image() |
| 77 | + with Image.open(f) as im: |
| 78 | + assert IptcImagePlugin.getiptcinfo(im) == { |
| 79 | + (3, 60): b"\x01\x00", |
| 80 | + (3, 120): b"\x01", |
| 81 | + (3, 20): b"\x01", |
| 82 | + (3, 30): b"\x01", |
| 83 | + } |
| 84 | + |
| 85 | + |
27 | 86 | def test_getiptcinfo_jpg_none() -> None:
|
28 | 87 | # Arrange
|
29 | 88 | with hopper() as im:
|
|
0 commit comments