diff --git a/Tests/images/hopper_rle8_row_overflow.bmp b/Tests/images/hopper_rle8_row_overflow.bmp new file mode 100644 index 000000000..d606dc3e4 Binary files /dev/null and b/Tests/images/hopper_rle8_row_overflow.bmp differ diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py index e0c70f037..15b4b3670 100644 --- a/Tests/test_file_bmp.py +++ b/Tests/test_file_bmp.py @@ -134,6 +134,11 @@ def test_rle8(): with Image.open("Tests/images/hopper_rle8.bmp") as im: assert_image_similar_tofile(im.convert("RGB"), "Tests/images/hopper.bmp", 12) + # This test image has been manually hexedited + # to have rows with too much data + with Image.open("Tests/images/hopper_rle8_row_overflow.bmp") as im: + assert_image_similar_tofile(im.convert("RGB"), "Tests/images/hopper.bmp", 12) + def test_offset(): # This image has been hexedited diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index 650478db9..60617dce3 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -281,17 +281,23 @@ class BmpRleDecoder(ImageFile.PyDecoder): def decode(self, buffer): data = bytearray() + x = 0 while True: num_pixels = self.fd.read(1)[0] byte = self.fd.read(1) if num_pixels: # encoded mode + if x + num_pixels > self.state.xsize: + # Too much data for row + num_pixels = max(0, self.state.xsize - x) data += byte * num_pixels + x += num_pixels else: if byte[0] == 0: # end of line while len(data) % self.state.xsize != 0: data += b"\x00" + x = 0 elif byte[0] == 1: # end of bitmap break @@ -299,9 +305,11 @@ class BmpRleDecoder(ImageFile.PyDecoder): # delta right, up = self.fd.read(2) data += b"\x00" * (right + up * self.state.xsize) + x = len(data) % self.state.xsize else: # absolute mode data += self.fd.read(byte[0]) + x += byte[0] # align to 16-bit word boundary if self.fd.tell() % 2 != 0: