From 073acd4c82ae77d8e5f052d73e1d73dde0a989d0 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 12 Mar 2022 17:32:15 +1100 Subject: [PATCH] Moved decoder names out of MODES --- Tests/test_file_ppm.py | 12 ++++++- src/PIL/PpmImagePlugin.py | 74 +++++++++++++++++---------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Tests/test_file_ppm.py b/Tests/test_file_ppm.py index ddeded6fb..8fe68d33e 100644 --- a/Tests/test_file_ppm.py +++ b/Tests/test_file_ppm.py @@ -51,35 +51,45 @@ def test_pnm(tmp_path): def test_plain_pbm(tmp_path): + # P1 with Image.open("Tests/images/hopper_1bit_plain.pbm") as im: + # P4 assert_image_equal_tofile(im, "Tests/images/hopper_1bit.pbm") def test_8bit_plain_pgm(tmp_path): + # P2 with Image.open("Tests/images/hopper_8bit_plain.pgm") as im: + # P5 assert_image_equal_tofile(im, "Tests/images/hopper_8bit.pgm") def test_8bit_plain_ppm(tmp_path): + # P3 with Image.open("Tests/images/hopper_8bit_plain.ppm") as im: + # P6 assert_image_equal_tofile(im, "Tests/images/hopper_8bit.ppm") def test_16bit_plain_pgm(tmp_path): + # P2 with maxval 2 ** 16 - 1 with Image.open("Tests/images/hopper_16bit_plain.pgm") as im: assert im.mode == "I" assert im.size == (128, 128) assert im.get_format_mimetype() == "image/x-portable-graymap" + # P5 with maxval 2 ** 16 - 1 assert_image_equal_tofile(im, "Tests/images/hopper_16bit.pgm") def test_32bit_plain_pgm(tmp_path): + # P2 with maxval 2 ** 31 - 1 with Image.open("Tests/images/hopper_32bit_plain.pgm") as im: assert im.mode == "I" assert im.size == (128, 128) assert im.get_format_mimetype() == "image/x-portable-graymap" + # P5 with maxval 2 ** 31 - 1 assert_image_equal_tofile(im, "Tests/images/hopper_32bit.pgm") @@ -187,7 +197,7 @@ def test_magic(tmp_path): def test_header_with_comments(tmp_path): path = str(tmp_path / "temp.ppm") with open(path, "wb") as f: - f.write(b"P6 #comment\n#comment\r 12#comment\r8\n128 #comment\n255\n") + f.write(b"P6 #comment\n#comment\r12#comment\r8\n128 #comment\n255\n") with Image.open(path) as im: assert im.size == (128, 128) diff --git a/src/PIL/PpmImagePlugin.py b/src/PIL/PpmImagePlugin.py index cae078d02..497b98395 100644 --- a/src/PIL/PpmImagePlugin.py +++ b/src/PIL/PpmImagePlugin.py @@ -23,20 +23,19 @@ from . import Image, ImageFile b_whitespace = b"\x20\x09\x0a\x0b\x0c\x0d" MODES = { - # standard, plain - b"P1": ("ppm_plain", "1"), - b"P2": ("ppm_plain", "L"), - b"P3": ("ppm_plain", "RGB"), - # standard, raw - b"P4": ("raw", "1"), - b"P5": ("raw", "L"), - b"P6": ("raw", "RGB"), + # standard + b"P1": "1", + b"P2": "L", + b"P3": "RGB", + b"P4": "1", + b"P5": "L", + b"P6": "RGB", # extensions - b"P0CMYK": ("raw", "CMYK"), + b"P0CMYK": "CMYK", # PIL extensions (for test purposes only) - b"PyP": ("raw", "P"), - b"PyRGBA": ("raw", "RGBA"), - b"PyCMYK": ("raw", "CMYK"), + b"PyP": "P", + b"PyRGBA": "RGBA", + b"PyCMYK": "CMYK", } @@ -90,18 +89,16 @@ class PpmImageFile(ImageFile.ImageFile): def _open(self): magic_number = self._read_magic() try: - decoder, mode = MODES[magic_number] + mode = MODES[magic_number] except KeyError: raise SyntaxError("not a PPM file") - self.custom_mimetype = { - b"P1": "image/x-portable-bitmap", - b"P2": "image/x-portable-graymap", - b"P3": "image/x-portable-pixmap", - b"P4": "image/x-portable-bitmap", - b"P5": "image/x-portable-graymap", - b"P6": "image/x-portable-pixmap", - }.get(magic_number) + if magic_number in (b"P1", b"P4"): + self.custom_mimetype = "image/x-portable-bitmap" + elif magic_number in (b"P2", b"P5"): + self.custom_mimetype = "image/x-portable-graymap" + elif magic_number in (b"P3", b"P6"): + self.custom_mimetype = "image/x-portable-pixmap" for ix in range(3): token = int(self._read_token()) @@ -127,14 +124,12 @@ class PpmImageFile(ImageFile.ImageFile): self.mode = "I" rawmode = "I;32B" + decoder_name = "raw" + if magic_number in (b"P1", b"P2", b"P3"): + decoder_name = "ppm_plain" self._size = xsize, ysize self.tile = [ - ( - decoder, # decoder - (0, 0, xsize, ysize), # region: whole image - self.fp.tell(), # offset to image data - (rawmode, 0, 1), # parameters for decoder - ) + (decoder_name, (0, 0, xsize, ysize), self.fp.tell(), (rawmode, 0, 1)) ] @@ -145,8 +140,8 @@ class PpmImageFile(ImageFile.ImageFile): class PpmPlainDecoder(ImageFile.PyDecoder): _pulls_fd = True - def _read_block(self, block_size=10**6): - return bytearray(self.fd.read(block_size)) + def _read_block(self): + return self.fd.read(10**6) def _find_comment_end(self, block, start=0): a = block.find(b"\n", start) @@ -155,10 +150,9 @@ class PpmPlainDecoder(ImageFile.PyDecoder): def _ignore_comments(self, block): """ - Deletes comments from block. If comment does not end in this - block, raises a flag. + Deletes comments from block. + If comment does not end in this block, raises a flag. """ - comment_spans = False while True: comment_start = block.find(b"#") # look for next comment @@ -166,9 +160,8 @@ class PpmPlainDecoder(ImageFile.PyDecoder): break comment_end = self._find_comment_end(block, comment_start) if comment_end != -1: # comment ends in this block - block = ( - block[:comment_start] + block[comment_end + 1 :] - ) # delete comment + # delete comment + block = block[:comment_start] + block[comment_end + 1 :] else: # last comment continues to next block(s) block = block[:comment_start] comment_spans = True @@ -177,9 +170,8 @@ class PpmPlainDecoder(ImageFile.PyDecoder): def _decode_bitonal(self): """ - The reason this is a separate method is that in the plain PBM - format all data tokens are exactly one byte, and so the - inter-token whitespace is optional. + This is a separate method because the plain PBM format all data tokens + are exactly one byte, and so the inter-token whitespace is optional. """ decoded_data = bytearray() total_tokens = self.size @@ -217,10 +209,8 @@ class PpmPlainDecoder(ImageFile.PyDecoder): def _decode_blocks(self, channels=1, depth=8): decoded_data = bytearray() - if depth == 32: - maxval = 2**31 - 1 # HACK: 32-bit grayscale uses signed int - else: - maxval = 2**depth - 1 # FIXME: should be passed by _open + # HACK: 32-bit grayscale uses signed int + maxval = 2 ** (31 if depth == 32 else depth) - 1 max_len = 10 bytes_per_sample = depth // 8 total_tokens = self.size * channels