From 329bb82406b7dcd0f24a30064441726e585b5744 Mon Sep 17 00:00:00 2001 From: Joel Ray Holveck Date: Mon, 1 Jun 2026 19:34:12 -0700 Subject: [PATCH 1/3] Fix Pillow examples using frombuffer The Pillow docs recommend always using the decoder arguments when using frombuffer; see https://pillow.readthedocs.io/en/stable/reference/Image.html --- demos/cat-detector.py | 2 +- demos/tinytv-stream-simple.py | 2 +- demos/tinytv-stream.py | 2 +- demos/video-capture-simple.py | 2 +- docs/source/examples/pil.py | 4 ++-- docs/source/release-history/v11.0.0.md | 10 +++++++++- src/tests/third_party/test_pil.py | 2 +- 7 files changed, 16 insertions(+), 8 deletions(-) diff --git a/demos/cat-detector.py b/demos/cat-detector.py index c274909f..cde7d833 100755 --- a/demos/cat-detector.py +++ b/demos/cat-detector.py @@ -281,7 +281,7 @@ def main() -> None: # We transfer the image from MSS to PyTorch via a Pillow Image. Faster approaches exist (see # screenshot_to_tensor), but PIL is more readable. The bulk of the time in this program is spent doing # the AI work, so we just use the most convenient mechanism. - img = Image.frombuffer("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX") + img = Image.frombuffer("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX", 0, 1) # We explicitly convert it to a tensor here, even though Torchvision can also convert it in the preprocess # step. This is so that we send it to the GPU before we do the preprocessing: PIL Images are always on diff --git a/demos/tinytv-stream-simple.py b/demos/tinytv-stream-simple.py index 4fe9ef13..c10129b8 100755 --- a/demos/tinytv-stream-simple.py +++ b/demos/tinytv-stream-simple.py @@ -97,7 +97,7 @@ def main() -> None: # The next step is to resize the image to fit the TinyTV's screen. There's a great image # manipulation library called PIL, or Pillow, that can do that. Let's transfer the raw pixels in # the ScreenShot object into a PIL Image. - original_image = Image.frombuffer("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX") + original_image = Image.frombuffer("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX", 0, 1) # Now, we can resize it. The resize method may stretch the image to make it match the TinyTV's # screen; the advanced demo gives other options. Using a reducing gap is optional, but speeds up diff --git a/demos/tinytv-stream.py b/demos/tinytv-stream.py index 83d62425..c2781fcf 100755 --- a/demos/tinytv-stream.py +++ b/demos/tinytv-stream.py @@ -348,7 +348,7 @@ def capture_image( while True: sct_img = sct.grab(rect) - pil_img = Image.frombuffer("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX") + pil_img = Image.frombuffer("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX", 0, 1) yield pil_img diff --git a/demos/video-capture-simple.py b/demos/video-capture-simple.py index ad39d32b..0e33b58f 100755 --- a/demos/video-capture-simple.py +++ b/demos/video-capture-simple.py @@ -129,7 +129,7 @@ def main() -> None: # use PIL: you can create an Image from the screenshot, and create a VideoFrame from that. That said, # if you want to boost the fps rate by about 50%, check out the full demo, and search for # from_numpy_buffer. - img = Image.frombuffer("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX") + img = Image.frombuffer("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX", 0, 1) frame = av.VideoFrame.from_image(img) # When we encode frames, we get back a list of packets. Often, we'll get no packets at first: the diff --git a/docs/source/examples/pil.py b/docs/source/examples/pil.py index 557e869c..f888a4e3 100644 --- a/docs/source/examples/pil.py +++ b/docs/source/examples/pil.py @@ -15,9 +15,9 @@ sct_img = sct.grab(monitor) # Create the Image - img = Image.frombuffer("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX") + img = Image.frombuffer("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX", 0, 1) # The same, but less efficient: - # img = Image.frombuffer('RGB', sct_img.size, sct_img.rgb, 'raw', 'RGB') + # img = Image.frombuffer('RGB', sct_img.size, sct_img.rgb, 'raw', 'RGB', 0, 1) # And save it! output = f"monitor-{num}.png" diff --git a/docs/source/release-history/v11.0.0.md b/docs/source/release-history/v11.0.0.md index 15ed8b8c..5d29b151 100644 --- a/docs/source/release-history/v11.0.0.md +++ b/docs/source/release-history/v11.0.0.md @@ -15,7 +15,8 @@ writing, but should be by the time we release 11.0!) #### ScreenShot attributes -The {py:attr}`mss.ScreenShot.raw` attribute has been removed. Use the {py:attr}`mss.ScreenShot.bgra` property instead. +The {py:attr}`mss.ScreenShot.raw` attribute has been deprecated, and will soon be removed. Use the +{py:attr}`mss.ScreenShot.bgra` property instead. The {py:attr}`mss.ScreenShot.bgra` and {py:attr}`mss.ScreenShot.rgb` properties now will return read-only bytes-like {py:type}`memoryview` objects, not necessarily {py:type}`bytes` or {py:type}`bytearray` objects. For practical use @@ -36,3 +37,10 @@ Device contexts are now acquired and released within each `grab()` call, allowin ### General Improvements The MSS context object will now always surface inner exceptions, even if `__exit__` may also generate an exception during tear-down. + +### Documentation + +The documentation has received numerous small improvements. A few highlights: + +* The Pillow examples and demos using {py:meth}`PIL.Image.frombuffer` now explicitly specify the decoder arguments, + as recommended by Pillow. diff --git a/src/tests/third_party/test_pil.py b/src/tests/third_party/test_pil.py index 586e1425..a04bbb79 100644 --- a/src/tests/third_party/test_pil.py +++ b/src/tests/third_party/test_pil.py @@ -37,7 +37,7 @@ def test_pil_bgra(mss_impl: Callable[..., MSS]) -> None: with mss_impl() as sct: sct_img = sct.grab(box) - img = Image.frombuffer("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX") + img = Image.frombuffer("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX", 0, 1) assert img.mode == "RGB" assert img.size == sct_img.size From ae92bc445d5a57accd0f0fa40a7cc1ce7d454d92 Mon Sep 17 00:00:00 2001 From: Joel Ray Holveck Date: Mon, 1 Jun 2026 19:40:49 -0700 Subject: [PATCH 2/3] Add PR number to release notes --- docs/source/release-history/v11.0.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/release-history/v11.0.0.md b/docs/source/release-history/v11.0.0.md index 5d29b151..db82c093 100644 --- a/docs/source/release-history/v11.0.0.md +++ b/docs/source/release-history/v11.0.0.md @@ -43,4 +43,4 @@ The MSS context object will now always surface inner exceptions, even if `__exit The documentation has received numerous small improvements. A few highlights: * The Pillow examples and demos using {py:meth}`PIL.Image.frombuffer` now explicitly specify the decoder arguments, - as recommended by Pillow. + as recommended by Pillow. (#535) From 8614e00dbe6c9bf38ffc3f23b4c1166dfca62537 Mon Sep 17 00:00:00 2001 From: Joel Holveck Date: Mon, 1 Jun 2026 20:59:57 -0700 Subject: [PATCH 3/3] Remove a release notes change that was put in this PR by mistake --- docs/source/release-history/v11.0.0.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/release-history/v11.0.0.md b/docs/source/release-history/v11.0.0.md index db82c093..50ca654b 100644 --- a/docs/source/release-history/v11.0.0.md +++ b/docs/source/release-history/v11.0.0.md @@ -15,8 +15,7 @@ writing, but should be by the time we release 11.0!) #### ScreenShot attributes -The {py:attr}`mss.ScreenShot.raw` attribute has been deprecated, and will soon be removed. Use the -{py:attr}`mss.ScreenShot.bgra` property instead. +The {py:attr}`mss.ScreenShot.raw` attribute has been removed. Use the {py:attr}`mss.ScreenShot.bgra` property instead. The {py:attr}`mss.ScreenShot.bgra` and {py:attr}`mss.ScreenShot.rgb` properties now will return read-only bytes-like {py:type}`memoryview` objects, not necessarily {py:type}`bytes` or {py:type}`bytearray` objects. For practical use