2828# EPS test files with binary preview
2929FILE3 = "Tests/images/binary_preview_map.eps"
3030
31+ # Three unsigned 32bit little-endian values:
32+ # 0xC6D3D0C5 magic number
33+ # byte position of start of postscript section (12)
34+ # byte length of postscript section (0)
35+ # this byte length isn't valid, but we don't read it
36+ simple_binary_header = b"\xc5 \xd0 \xd3 \xc6 \x0c \x00 \x00 \x00 \x00 \x00 \x00 \x00 "
37+
38+ # taken from page 8 of the specification
39+ # https://web.archive.org/web/20220120164601/https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/5002.EPSF_Spec.pdf
40+ simple_eps_file = (
41+ b"%!PS-Adobe-3.0 EPSF-3.0" ,
42+ b"%%BoundingBox: 5 5 105 105" ,
43+ b"10 setlinewidth" ,
44+ b"10 10 moveto" ,
45+ b"0 90 rlineto 90 0 rlineto 0 -90 rlineto closepath" ,
46+ b"stroke" ,
47+ )
48+ simple_eps_file_with_comments = (
49+ simple_eps_file [:1 ]
50+ + (
51+ b"%%Comment1: Some Value" ,
52+ b"%%SecondComment: Another Value" ,
53+ )
54+ + simple_eps_file [1 :]
55+ )
56+ simple_eps_file_without_version = simple_eps_file [1 :]
57+ simple_eps_file_without_boundingbox = simple_eps_file [:1 ] + simple_eps_file [2 :]
58+ simple_eps_file_with_invalid_boundingbox = (
59+ simple_eps_file [:1 ] + (b"%%BoundingBox: a b c d" ,) + simple_eps_file [2 :]
60+ )
61+ simple_eps_file_with_invalid_boundingbox_valid_imagedata = (
62+ simple_eps_file_with_invalid_boundingbox + (b"%ImageData: 100 100 8 3" ,)
63+ )
64+ simple_eps_file_with_long_ascii_comment = (
65+ simple_eps_file [:2 ] + (b"%%Comment: " + b"X" * 300 ,) + simple_eps_file [2 :]
66+ )
67+ simple_eps_file_with_long_binary_data = (
68+ simple_eps_file [:2 ]
69+ + (
70+ b"%%BeginBinary: 300" ,
71+ b"\0 " * 300 ,
72+ b"%%EndBinary" ,
73+ )
74+ + simple_eps_file [2 :]
75+ )
3176
32- @pytest .mark .skipif (not HAS_GHOSTSCRIPT , reason = "Ghostscript not available" )
33- def test_sanity ():
34- # Regular scale
35- with Image .open (FILE1 ) as image1 :
36- image1 .load ()
37- assert image1 .mode == "RGB"
38- assert image1 .size == (460 , 352 )
39- assert image1 .format == "EPS"
40-
41- with Image .open (FILE2 ) as image2 :
42- image2 .load ()
43- assert image2 .mode == "RGB"
44- assert image2 .size == (360 , 252 )
45- assert image2 .format == "EPS"
46-
47- # Double scale
48- with Image .open (FILE1 ) as image1_scale2 :
49- image1_scale2 .load (scale = 2 )
50- assert image1_scale2 .mode == "RGB"
51- assert image1_scale2 .size == (920 , 704 )
52- assert image1_scale2 .format == "EPS"
5377
54- with Image .open (FILE2 ) as image2_scale2 :
55- image2_scale2 .load (scale = 2 )
56- assert image2_scale2 .mode == "RGB"
57- assert image2_scale2 .size == (720 , 504 )
58- assert image2_scale2 .format == "EPS"
78+ @pytest .mark .skipif (not HAS_GHOSTSCRIPT , reason = "Ghostscript not available" )
79+ @pytest .mark .parametrize (
80+ ("filename" , "size" ), ((FILE1 , (460 , 352 )), (FILE2 , (360 , 252 )))
81+ )
82+ @pytest .mark .parametrize ("scale" , (1 , 2 ))
83+ def test_sanity (filename , size , scale ):
84+ expected_size = tuple (s * scale for s in size )
85+ with Image .open (filename ) as image :
86+ image .load (scale = scale )
87+ assert image .mode == "RGB"
88+ assert image .size == expected_size
89+ assert image .format == "EPS"
5990
6091
6192@pytest .mark .skipif (not HAS_GHOSTSCRIPT , reason = "Ghostscript not available" )
@@ -69,11 +100,72 @@ def test_load():
69100
70101def test_invalid_file ():
71102 invalid_file = "Tests/images/flower.jpg"
72-
73103 with pytest .raises (SyntaxError ):
74104 EpsImagePlugin .EpsImageFile (invalid_file )
75105
76106
107+ def test_binary_header_only ():
108+ data = io .BytesIO (simple_binary_header )
109+ with pytest .raises (SyntaxError , match = 'EPS header missing "%!PS-Adobe" comment' ):
110+ EpsImagePlugin .EpsImageFile (data )
111+
112+
113+ @pytest .mark .parametrize ("prefix" , (b"" , simple_binary_header ))
114+ def test_missing_version_comment (prefix ):
115+ data = io .BytesIO (prefix + b"\n " .join (simple_eps_file_without_version ))
116+ with pytest .raises (SyntaxError ):
117+ EpsImagePlugin .EpsImageFile (data )
118+
119+
120+ @pytest .mark .parametrize ("prefix" , (b"" , simple_binary_header ))
121+ def test_missing_boundingbox_comment (prefix ):
122+ data = io .BytesIO (prefix + b"\n " .join (simple_eps_file_without_boundingbox ))
123+ with pytest .raises (SyntaxError , match = 'EPS header missing "%%BoundingBox" comment' ):
124+ EpsImagePlugin .EpsImageFile (data )
125+
126+
127+ @pytest .mark .parametrize ("prefix" , (b"" , simple_binary_header ))
128+ def test_invalid_boundingbox_comment (prefix ):
129+ data = io .BytesIO (prefix + b"\n " .join (simple_eps_file_with_invalid_boundingbox ))
130+ with pytest .raises (OSError , match = "cannot determine EPS bounding box" ):
131+ EpsImagePlugin .EpsImageFile (data )
132+
133+
134+ @pytest .mark .parametrize ("prefix" , (b"" , simple_binary_header ))
135+ def test_invalid_boundingbox_comment_valid_imagedata_comment (prefix ):
136+ data = io .BytesIO (
137+ prefix + b"\n " .join (simple_eps_file_with_invalid_boundingbox_valid_imagedata )
138+ )
139+ with Image .open (data ) as img :
140+ assert img .mode == "RGB"
141+ assert img .size == (100 , 100 )
142+ assert img .format == "EPS"
143+
144+
145+ @pytest .mark .parametrize ("prefix" , (b"" , simple_binary_header ))
146+ def test_ascii_comment_too_long (prefix ):
147+ data = io .BytesIO (prefix + b"\n " .join (simple_eps_file_with_long_ascii_comment ))
148+ with pytest .raises (SyntaxError , match = "not an EPS file" ):
149+ EpsImagePlugin .EpsImageFile (data )
150+
151+
152+ @pytest .mark .parametrize ("prefix" , (b"" , simple_binary_header ))
153+ def test_long_binary_data (prefix ):
154+ data = io .BytesIO (prefix + b"\n " .join (simple_eps_file_with_long_binary_data ))
155+ EpsImagePlugin .EpsImageFile (data )
156+
157+
158+ @pytest .mark .skipif (not HAS_GHOSTSCRIPT , reason = "Ghostscript not available" )
159+ @pytest .mark .parametrize ("prefix" , (b"" , simple_binary_header ))
160+ def test_load_long_binary_data (prefix ):
161+ data = io .BytesIO (prefix + b"\n " .join (simple_eps_file_with_long_binary_data ))
162+ with Image .open (data ) as img :
163+ img .load ()
164+ assert img .mode == "RGB"
165+ assert img .size == (100 , 100 )
166+ assert img .format == "EPS"
167+
168+
77169@mark_if_feature_version (
78170 pytest .mark .valgrind_known_error , "libjpeg_turbo" , "2.0" , reason = "Known Failing"
79171)
@@ -100,7 +192,7 @@ def test_showpage():
100192 with Image .open ("Tests/images/reqd_showpage.png" ) as target :
101193 # should not crash/hang
102194 plot_image .load ()
103- # fonts could be slightly different
195+ # fonts could be slightly different
104196 assert_image_similar (plot_image , target , 6 )
105197
106198
@@ -111,7 +203,7 @@ def test_transparency():
111203 assert plot_image .mode == "RGBA"
112204
113205 with Image .open ("Tests/images/reqd_showpage_transparency.png" ) as target :
114- # fonts could be slightly different
206+ # fonts could be slightly different
115207 assert_image_similar (plot_image , target , 6 )
116208
117209
@@ -206,7 +298,6 @@ def test_resize(filename):
206298@pytest .mark .parametrize ("filename" , (FILE1 , FILE2 ))
207299def test_thumbnail (filename ):
208300 # Issue #619
209- # Arrange
210301 with Image .open (filename ) as im :
211302 new_size = (100 , 100 )
212303 im .thumbnail (new_size )
@@ -220,7 +311,7 @@ def test_read_binary_preview():
220311 pass
221312
222313
223- def test_readline (tmp_path ):
314+ def test_readline_psfile (tmp_path ):
224315 # check all the freaking line endings possible from the spec
225316 # test_string = u'something\r\nelse\n\rbaz\rbif\n'
226317 line_endings = ["\r \n " , "\n " , "\n \r " , "\r " ]
@@ -237,7 +328,8 @@ def _test_readline(t, ending):
237328
238329 def _test_readline_io_psfile (test_string , ending ):
239330 f = io .BytesIO (test_string .encode ("latin-1" ))
240- t = EpsImagePlugin .PSFile (f )
331+ with pytest .warns (DeprecationWarning ):
332+ t = EpsImagePlugin .PSFile (f )
241333 _test_readline (t , ending )
242334
243335 def _test_readline_file_psfile (test_string , ending ):
@@ -246,7 +338,8 @@ def _test_readline_file_psfile(test_string, ending):
246338 w .write (test_string .encode ("latin-1" ))
247339
248340 with open (f , "rb" ) as r :
249- t = EpsImagePlugin .PSFile (r )
341+ with pytest .warns (DeprecationWarning ):
342+ t = EpsImagePlugin .PSFile (r )
250343 _test_readline (t , ending )
251344
252345 for ending in line_endings :
@@ -255,6 +348,25 @@ def _test_readline_file_psfile(test_string, ending):
255348 _test_readline_file_psfile (s , ending )
256349
257350
351+ def test_psfile_deprecation ():
352+ with pytest .warns (DeprecationWarning ):
353+ EpsImagePlugin .PSFile (None )
354+
355+
356+ @pytest .mark .parametrize ("prefix" , (b"" , simple_binary_header ))
357+ @pytest .mark .parametrize (
358+ "line_ending" ,
359+ (b"\r \n " , b"\n " , b"\n \r " , b"\r " ),
360+ )
361+ def test_readline (prefix , line_ending ):
362+ simple_file = prefix + line_ending .join (simple_eps_file_with_comments )
363+ data = io .BytesIO (simple_file )
364+ test_file = EpsImagePlugin .EpsImageFile (data )
365+ assert test_file .info ["Comment1" ] == "Some Value"
366+ assert test_file .info ["SecondComment" ] == "Another Value"
367+ assert test_file .size == (100 , 100 )
368+
369+
258370@pytest .mark .parametrize (
259371 "filename" ,
260372 (
0 commit comments