33
44import pytest
55
6- from PIL import Image , UnidentifiedImageError
6+ from PIL import Image , PpmImagePlugin
77
88from .helper import assert_image_equal_tofile , assert_image_similar , hopper
99
@@ -22,6 +22,21 @@ def test_sanity():
2222@pytest .mark .parametrize (
2323 "data, mode, pixels" ,
2424 (
25+ (b"P2 3 1 4 0 2 4" , "L" , (0 , 128 , 255 )),
26+ (b"P2 3 1 257 0 128 257" , "I" , (0 , 32640 , 65535 )),
27+ # P3 with maxval < 255
28+ (
29+ b"P3 3 1 17 0 1 2 8 9 10 15 16 17" ,
30+ "RGB" ,
31+ ((0 , 15 , 30 ), (120 , 135 , 150 ), (225 , 240 , 255 )),
32+ ),
33+ # P3 with maxval > 255
34+ # Scale down to 255, since there is no RGB mode with more than 8-bit
35+ (
36+ b"P3 3 1 257 0 1 2 128 129 130 256 257 257" ,
37+ "RGB" ,
38+ ((0 , 1 , 2 ), (127 , 128 , 129 ), (254 , 255 , 255 )),
39+ ),
2540 (b"P5 3 1 4 \x00 \x02 \x04 " , "L" , (0 , 128 , 255 )),
2641 (b"P5 3 1 257 \x00 \x00 \x00 \x80 \x01 \x01 " , "I" , (0 , 32640 , 65535 )),
2742 # P6 with maxval < 255
@@ -35,7 +50,6 @@ def test_sanity():
3550 ),
3651 ),
3752 # P6 with maxval > 255
38- # Scale down to 255, since there is no RGB mode with more than 8-bit
3953 (
4054 b"P6 3 1 257 \x00 \x00 \x00 \x01 \x00 \x02 "
4155 b"\x00 \x80 \x00 \x81 \x00 \x82 \x01 \x00 \x01 \x01 \xFF \xFF " ,
@@ -85,14 +99,111 @@ def test_pnm(tmp_path):
8599 assert_image_equal_tofile (im , f )
86100
87101
88- def test_magic (tmp_path ):
102+ @pytest .mark .parametrize (
103+ "plain_path, raw_path" ,
104+ (
105+ (
106+ "Tests/images/hopper_1bit_plain.pbm" , # P1
107+ "Tests/images/hopper_1bit.pbm" , # P4
108+ ),
109+ (
110+ "Tests/images/hopper_8bit_plain.pgm" , # P2
111+ "Tests/images/hopper_8bit.pgm" , # P5
112+ ),
113+ (
114+ "Tests/images/hopper_8bit_plain.ppm" , # P3
115+ "Tests/images/hopper_8bit.ppm" , # P6
116+ ),
117+ ),
118+ )
119+ def test_plain (plain_path , raw_path ):
120+ with Image .open (plain_path ) as im :
121+ assert_image_equal_tofile (im , raw_path )
122+
123+
124+ def test_16bit_plain_pgm ():
125+ # P2 with maxval 2 ** 16 - 1
126+ with Image .open ("Tests/images/hopper_16bit_plain.pgm" ) as im :
127+ assert im .mode == "I"
128+ assert im .size == (128 , 128 )
129+ assert im .get_format_mimetype () == "image/x-portable-graymap"
130+
131+ # P5 with maxval 2 ** 16 - 1
132+ assert_image_equal_tofile (im , "Tests/images/hopper_16bit.pgm" )
133+
134+
135+ @pytest .mark .parametrize (
136+ "header, data, comment_count" ,
137+ (
138+ (b"P1\n 2 2" , b"1010" , 10 ** 6 ),
139+ (b"P2\n 3 1\n 4" , b"0 2 4" , 1 ),
140+ (b"P3\n 2 2\n 255" , b"0 0 0 001 1 1 2 2 2 255 255 255" , 10 ** 6 ),
141+ ),
142+ )
143+ def test_plain_data_with_comment (tmp_path , header , data , comment_count ):
144+ path1 = str (tmp_path / "temp1.ppm" )
145+ path2 = str (tmp_path / "temp2.ppm" )
146+ comment = b"# comment" * comment_count
147+ with open (path1 , "wb" ) as f1 , open (path2 , "wb" ) as f2 :
148+ f1 .write (header + b"\n \n " + data )
149+ f2 .write (header + b"\n " + comment + b"\n " + data + comment )
150+
151+ with Image .open (path1 ) as im :
152+ assert_image_equal_tofile (im , path2 )
153+
154+
155+ @pytest .mark .parametrize ("data" , (b"P1\n 128 128\n " , b"P3\n 128 128\n 255\n " ))
156+ def test_plain_truncated_data (tmp_path , data ):
89157 path = str (tmp_path / "temp.ppm" )
90158 with open (path , "wb" ) as f :
91- f .write (b"PyInvalid" )
159+ f .write (data )
92160
93- with pytest .raises (UnidentifiedImageError ):
94- with Image .open (path ):
95- pass
161+ with Image .open (path ) as im :
162+ with pytest .raises (ValueError ):
163+ im .load ()
164+
165+
166+ @pytest .mark .parametrize ("data" , (b"P1\n 128 128\n 1009" , b"P3\n 128 128\n 255\n 100A" ))
167+ def test_plain_invalid_data (tmp_path , data ):
168+ path = str (tmp_path / "temp.ppm" )
169+ with open (path , "wb" ) as f :
170+ f .write (data )
171+
172+ with Image .open (path ) as im :
173+ with pytest .raises (ValueError ):
174+ im .load ()
175+
176+
177+ @pytest .mark .parametrize (
178+ "data" ,
179+ (
180+ b"P3\n 128 128\n 255\n 012345678910" , # half token too long
181+ b"P3\n 128 128\n 255\n 012345678910 0" , # token too long
182+ ),
183+ )
184+ def test_plain_ppm_token_too_long (tmp_path , data ):
185+ path = str (tmp_path / "temp.ppm" )
186+ with open (path , "wb" ) as f :
187+ f .write (data )
188+
189+ with Image .open (path ) as im :
190+ with pytest .raises (ValueError ):
191+ im .load ()
192+
193+
194+ def test_plain_ppm_value_too_large (tmp_path ):
195+ path = str (tmp_path / "temp.ppm" )
196+ with open (path , "wb" ) as f :
197+ f .write (b"P3\n 128 128\n 255\n 256" )
198+
199+ with Image .open (path ) as im :
200+ with pytest .raises (ValueError ):
201+ im .load ()
202+
203+
204+ def test_magic ():
205+ with pytest .raises (SyntaxError ):
206+ PpmImagePlugin .PpmImageFile (fp = BytesIO (b"PyInvalid" ))
96207
97208
98209def test_header_with_comments (tmp_path ):
@@ -114,7 +225,7 @@ def test_non_integer_token(tmp_path):
114225 pass
115226
116227
117- def test_token_too_long (tmp_path ):
228+ def test_header_token_too_long (tmp_path ):
118229 path = str (tmp_path / "temp.ppm" )
119230 with open (path , "wb" ) as f :
120231 f .write (b"P6\n 01234567890" )
0 commit comments