Skip to content

Commit 073acd4

Browse files
committed
Moved decoder names out of MODES
1 parent 0215175 commit 073acd4

File tree

2 files changed

+43
-43
lines changed

2 files changed

+43
-43
lines changed

Tests/test_file_ppm.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,35 +51,45 @@ def test_pnm(tmp_path):
5151

5252

5353
def test_plain_pbm(tmp_path):
54+
# P1
5455
with Image.open("Tests/images/hopper_1bit_plain.pbm") as im:
56+
# P4
5557
assert_image_equal_tofile(im, "Tests/images/hopper_1bit.pbm")
5658

5759

5860
def test_8bit_plain_pgm(tmp_path):
61+
# P2
5962
with Image.open("Tests/images/hopper_8bit_plain.pgm") as im:
63+
# P5
6064
assert_image_equal_tofile(im, "Tests/images/hopper_8bit.pgm")
6165

6266

6367
def test_8bit_plain_ppm(tmp_path):
68+
# P3
6469
with Image.open("Tests/images/hopper_8bit_plain.ppm") as im:
70+
# P6
6571
assert_image_equal_tofile(im, "Tests/images/hopper_8bit.ppm")
6672

6773

6874
def test_16bit_plain_pgm(tmp_path):
75+
# P2 with maxval 2 ** 16 - 1
6976
with Image.open("Tests/images/hopper_16bit_plain.pgm") as im:
7077
assert im.mode == "I"
7178
assert im.size == (128, 128)
7279
assert im.get_format_mimetype() == "image/x-portable-graymap"
7380

81+
# P5 with maxval 2 ** 16 - 1
7482
assert_image_equal_tofile(im, "Tests/images/hopper_16bit.pgm")
7583

7684

7785
def test_32bit_plain_pgm(tmp_path):
86+
# P2 with maxval 2 ** 31 - 1
7887
with Image.open("Tests/images/hopper_32bit_plain.pgm") as im:
7988
assert im.mode == "I"
8089
assert im.size == (128, 128)
8190
assert im.get_format_mimetype() == "image/x-portable-graymap"
8291

92+
# P5 with maxval 2 ** 31 - 1
8393
assert_image_equal_tofile(im, "Tests/images/hopper_32bit.pgm")
8494

8595

@@ -187,7 +197,7 @@ def test_magic(tmp_path):
187197
def test_header_with_comments(tmp_path):
188198
path = str(tmp_path / "temp.ppm")
189199
with open(path, "wb") as f:
190-
f.write(b"P6 #comment\n#comment\r 12#comment\r8\n128 #comment\n255\n")
200+
f.write(b"P6 #comment\n#comment\r12#comment\r8\n128 #comment\n255\n")
191201

192202
with Image.open(path) as im:
193203
assert im.size == (128, 128)

src/PIL/PpmImagePlugin.py

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,19 @@
2323
b_whitespace = b"\x20\x09\x0a\x0b\x0c\x0d"
2424

2525
MODES = {
26-
# standard, plain
27-
b"P1": ("ppm_plain", "1"),
28-
b"P2": ("ppm_plain", "L"),
29-
b"P3": ("ppm_plain", "RGB"),
30-
# standard, raw
31-
b"P4": ("raw", "1"),
32-
b"P5": ("raw", "L"),
33-
b"P6": ("raw", "RGB"),
26+
# standard
27+
b"P1": "1",
28+
b"P2": "L",
29+
b"P3": "RGB",
30+
b"P4": "1",
31+
b"P5": "L",
32+
b"P6": "RGB",
3433
# extensions
35-
b"P0CMYK": ("raw", "CMYK"),
34+
b"P0CMYK": "CMYK",
3635
# PIL extensions (for test purposes only)
37-
b"PyP": ("raw", "P"),
38-
b"PyRGBA": ("raw", "RGBA"),
39-
b"PyCMYK": ("raw", "CMYK"),
36+
b"PyP": "P",
37+
b"PyRGBA": "RGBA",
38+
b"PyCMYK": "CMYK",
4039
}
4140

4241

@@ -90,18 +89,16 @@ def _read_token(self):
9089
def _open(self):
9190
magic_number = self._read_magic()
9291
try:
93-
decoder, mode = MODES[magic_number]
92+
mode = MODES[magic_number]
9493
except KeyError:
9594
raise SyntaxError("not a PPM file")
9695

97-
self.custom_mimetype = {
98-
b"P1": "image/x-portable-bitmap",
99-
b"P2": "image/x-portable-graymap",
100-
b"P3": "image/x-portable-pixmap",
101-
b"P4": "image/x-portable-bitmap",
102-
b"P5": "image/x-portable-graymap",
103-
b"P6": "image/x-portable-pixmap",
104-
}.get(magic_number)
96+
if magic_number in (b"P1", b"P4"):
97+
self.custom_mimetype = "image/x-portable-bitmap"
98+
elif magic_number in (b"P2", b"P5"):
99+
self.custom_mimetype = "image/x-portable-graymap"
100+
elif magic_number in (b"P3", b"P6"):
101+
self.custom_mimetype = "image/x-portable-pixmap"
105102

106103
for ix in range(3):
107104
token = int(self._read_token())
@@ -127,14 +124,12 @@ def _open(self):
127124
self.mode = "I"
128125
rawmode = "I;32B"
129126

127+
decoder_name = "raw"
128+
if magic_number in (b"P1", b"P2", b"P3"):
129+
decoder_name = "ppm_plain"
130130
self._size = xsize, ysize
131131
self.tile = [
132-
(
133-
decoder, # decoder
134-
(0, 0, xsize, ysize), # region: whole image
135-
self.fp.tell(), # offset to image data
136-
(rawmode, 0, 1), # parameters for decoder
137-
)
132+
(decoder_name, (0, 0, xsize, ysize), self.fp.tell(), (rawmode, 0, 1))
138133
]
139134

140135

@@ -145,8 +140,8 @@ def _open(self):
145140
class PpmPlainDecoder(ImageFile.PyDecoder):
146141
_pulls_fd = True
147142

148-
def _read_block(self, block_size=10**6):
149-
return bytearray(self.fd.read(block_size))
143+
def _read_block(self):
144+
return self.fd.read(10**6)
150145

151146
def _find_comment_end(self, block, start=0):
152147
a = block.find(b"\n", start)
@@ -155,20 +150,18 @@ def _find_comment_end(self, block, start=0):
155150

156151
def _ignore_comments(self, block):
157152
"""
158-
Deletes comments from block. If comment does not end in this
159-
block, raises a flag.
153+
Deletes comments from block.
154+
If comment does not end in this block, raises a flag.
160155
"""
161-
162156
comment_spans = False
163157
while True:
164158
comment_start = block.find(b"#") # look for next comment
165159
if comment_start == -1: # no comment found
166160
break
167161
comment_end = self._find_comment_end(block, comment_start)
168162
if comment_end != -1: # comment ends in this block
169-
block = (
170-
block[:comment_start] + block[comment_end + 1 :]
171-
) # delete comment
163+
# delete comment
164+
block = block[:comment_start] + block[comment_end + 1 :]
172165
else: # last comment continues to next block(s)
173166
block = block[:comment_start]
174167
comment_spans = True
@@ -177,9 +170,8 @@ def _ignore_comments(self, block):
177170

178171
def _decode_bitonal(self):
179172
"""
180-
The reason this is a separate method is that in the plain PBM
181-
format all data tokens are exactly one byte, and so the
182-
inter-token whitespace is optional.
173+
This is a separate method because the plain PBM format all data tokens
174+
are exactly one byte, and so the inter-token whitespace is optional.
183175
"""
184176
decoded_data = bytearray()
185177
total_tokens = self.size
@@ -217,10 +209,8 @@ def _decode_bitonal(self):
217209

218210
def _decode_blocks(self, channels=1, depth=8):
219211
decoded_data = bytearray()
220-
if depth == 32:
221-
maxval = 2**31 - 1 # HACK: 32-bit grayscale uses signed int
222-
else:
223-
maxval = 2**depth - 1 # FIXME: should be passed by _open
212+
# HACK: 32-bit grayscale uses signed int
213+
maxval = 2 ** (31 if depth == 32 else depth) - 1
224214
max_len = 10
225215
bytes_per_sample = depth // 8
226216
total_tokens = self.size * channels

0 commit comments

Comments
 (0)