1
from __future__ import annotations
3
from pathlib import Path
7
from PIL import Image, ImageFile, PcxImagePlugin
9
from .helper import assert_image_equal, hopper
12
def _roundtrip(tmp_path: Path, im: Image.Image) -> None:
13
f = str(tmp_path / "temp.pcx")
15
with Image.open(f) as im2:
16
assert im2.mode == im.mode
17
assert im2.size == im.size
18
assert im2.format == "PCX"
19
assert im2.get_format_mimetype() == "image/x-pcx"
20
assert_image_equal(im2, im)
23
def test_sanity(tmp_path: Path) -> None:
24
for mode in ("1", "L", "P", "RGB"):
25
_roundtrip(tmp_path, hopper(mode))
28
im = Image.new("P", (1, 1))
29
im.putpalette((255, 0, 0))
30
_roundtrip(tmp_path, im)
33
f = str(tmp_path / "temp.pcx")
35
with pytest.raises(ValueError):
39
def test_invalid_file() -> None:
40
invalid_file = "Tests/images/flower.jpg"
42
with pytest.raises(SyntaxError):
43
PcxImagePlugin.PcxImageFile(invalid_file)
46
@pytest.mark.parametrize("mode", ("1", "L", "P", "RGB"))
47
def test_odd(tmp_path: Path, mode: str) -> None:
53
_roundtrip(tmp_path, hopper(mode).resize((511, 511)))
56
def test_odd_read() -> None:
58
with Image.open("Tests/images/odd_stride.pcx") as im:
61
assert im.size == (371, 150)
64
def test_pil184() -> None:
67
test_file = "Tests/images/pil184.pcx"
68
with Image.open(test_file) as im:
69
assert im.size == (447, 144)
70
assert im.tile[0][1] == (0, 0, 447, 144)
73
assert im.histogram()[0] + im.histogram()[255] == 447 * 144
76
def test_1px_width(tmp_path: Path) -> None:
77
im = Image.new("L", (1, 256))
82
_roundtrip(tmp_path, im)
85
def test_large_count(tmp_path: Path) -> None:
86
im = Image.new("L", (256, 1))
90
px[x, 0] = x // 67 * 67
91
_roundtrip(tmp_path, im)
94
def _test_buffer_overflow(tmp_path: Path, im: Image.Image, size: int = 1024) -> None:
95
_last = ImageFile.MAXBLOCK
96
ImageFile.MAXBLOCK = size
98
_roundtrip(tmp_path, im)
100
ImageFile.MAXBLOCK = _last
103
def test_break_in_count_overflow(tmp_path: Path) -> None:
104
im = Image.new("L", (256, 5))
106
assert px is not None
110
_test_buffer_overflow(tmp_path, im)
113
def test_break_one_in_loop(tmp_path: Path) -> None:
114
im = Image.new("L", (256, 5))
116
assert px is not None
120
_test_buffer_overflow(tmp_path, im)
123
def test_break_many_in_loop(tmp_path: Path) -> None:
124
im = Image.new("L", (256, 5))
126
assert px is not None
132
_test_buffer_overflow(tmp_path, im)
135
def test_break_one_at_end(tmp_path: Path) -> None:
136
im = Image.new("L", (256, 5))
138
assert px is not None
143
_test_buffer_overflow(tmp_path, im)
146
def test_break_many_at_end(tmp_path: Path) -> None:
147
im = Image.new("L", (256, 5))
149
assert px is not None
154
px[x * 2, 3] = 128 + 64
155
px[x + 256 - 4, 3] = 0
156
_test_buffer_overflow(tmp_path, im)
159
def test_break_padding(tmp_path: Path) -> None:
160
im = Image.new("L", (257, 5))
162
assert px is not None
168
_test_buffer_overflow(tmp_path, im)