From 4777a0b31820f184c01d550fa526400dc9b53eaf Mon Sep 17 00:00:00 2001 From: Kadir Can Ozden <101993364+bysiber@users.noreply.github.com> Date: Sat, 21 Feb 2026 15:21:48 +0300 Subject: [PATCH] Fix BMP RLE delta escape reading from wrong file position (#9443) Co-authored-by: Andrew Murray --- Tests/images/pal8rletrns.png | Bin 0 -> 4089 bytes Tests/test_file_bmp.py | 5 +++++ src/PIL/BmpImagePlugin.py | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Tests/images/pal8rletrns.png diff --git a/Tests/images/pal8rletrns.png b/Tests/images/pal8rletrns.png new file mode 100644 index 0000000000000000000000000000000000000000..2362266ef0287fd543aaae2b3769cbdf49386ce5 GIT binary patch literal 4089 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 I2Cqo{A2mRU6951J literal 0 HcmV?d00001 diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py index 28e863459..2e0394b3b 100644 --- a/Tests/test_file_bmp.py +++ b/Tests/test_file_bmp.py @@ -221,6 +221,11 @@ def test_rle8_eof(file_name: str, length: int) -> None: im.load() +def test_rle_delta() -> None: + with Image.open("Tests/images/bmp/q/pal8rletrns.bmp") as im: + assert_image_equal_tofile(im, "Tests/images/pal8rletrns.png") + + def test_unsupported_bmp_bitfields_layout() -> None: fp = io.BytesIO( o32(40) # header size diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index a12271370..5ee61b35b 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -369,7 +369,7 @@ class BmpRleDecoder(ImageFile.PyDecoder): bytes_read = self.fd.read(2) if len(bytes_read) < 2: break - right, up = self.fd.read(2) + right, up = bytes_read data += b"\x00" * (right + up * self.state.xsize) x = len(data) % self.state.xsize else: