Skip to content

Add convenience export methods to ScreenShot#14

Closed
jholveck wants to merge 18 commits into
mainfrom
feat-array-library-methods
Closed

Add convenience export methods to ScreenShot#14
jholveck wants to merge 18 commits into
mainfrom
feat-array-library-methods

Conversation

@jholveck

@jholveck jholveck commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Add convenience methods to mss.ScreenShot to export to PIL, NumPy, PyTorch, and TensorFlow. These are high-performance methods that can be used by end users for most common export tasks.

This also removes the burden from the user of figuring out the best way to, for instance, convert from BGRA to RGB: by putting the fastest techniques in these methods, we let users focus on their applications, and even get benefits as we make changes to things like buffer management that allow faster exports.

Extensive documentation is added, since these may end up being the most common way for end users to access pixel data.

This is also the first time we explicitly add any GPU support to MSS. This is a pretty small thing in MSS’s terms; we still are copying the framebuffer to CPU memory. But we’re now enabling fast, easy export to the common DL frameworks, which is where we’re seeing a rise in screen image usage lately.

These methods are tested in CI/CD with CPU only. On developer machines, they’re tested if the dev has installed PyTorch or TensorFlow (NumPy is already a prerequisite), including the CUDA paths if that’s available.

Summary by CodeRabbit

  • New Features

    • Added easy-to-use screenshot export options for Pillow, NumPy, PyTorch, and TensorFlow.
    • Improved demo and example code to use the new screenshot conversion methods directly.
    • Expanded screenshot handling guidance with clearer channel and layout options.
  • Documentation

    • Updated usage docs with new capture, pixel access, and memory-sharing explanations.
    • Added broader cross-references to external package documentation.
  • Bug Fixes

    • Streamlined image conversion paths for better consistency across platforms and frameworks.

Currently, this shares memory with the .raw bytearray in some cases.
We should consider whether we want to change that to always copy, or
just wait until we have the full shared buffer support.

This implementation always does the array manipulation on the CPU.
For PyTorch or TensorFlow, the user is likely to want to do the array
manipulation on the GPU for performance.  This is very easy to
implement.
Python 3.9 doesn't define TypeAlias, and it's not required in this
case, so we can just remove it.
The reverted change was from a temporary test, but I accidentally
included it in the commit.  It's not relevant to the issue at hand.
The docstrings weren't all in Sphinx format, and could use a little
clarification in places.

TensorFlow itself allows NumPy dtypes and DataType enums, so expand
to_tensorflow to accept those too.
The main point of this commit is to be explicit about the memory-sharing
semantics: mostly, that we don't guarantee memory sharing one way or
another.  More to the point, that if they modify the pixel data in one
of the exported objects, it may or may not affect the other exported
objects.

Memory sharing isn't expected to affect most users, since they
are unlikely to access the pixel data with two different exported
objects, but it's best to be explicit.

To have a good place to put the memory-sharing discussion, I added a new
section to the usage.rst file, listing the ways to access the pixel
data.  This is also where I documented the NumPy array interface
protocol, which previously didn't show up in our Sphinx docs.  (It might
have been in the docs for 10.1, which didn't use autodoc.)

I also put a discussion of the alpha channel in this new section: one
thing I keep forgetting is to delete the alpha channel when using
Matplotlib, and wondering why it's blank.

TODO: We probably should document `grab` in the usage.rst file for the
new section to make sense.

In the process, I've also added intersphinx links to libraries like PIL
and NumPy, so that our Sphinx docs will link to them.  While checking
that, I fixed a few other references (like referring to bytes with
:py:type:, when it's indexed under :py:class:).
Doc fixes.  Speed up converting to a NumPy array in RGB order.  That
sort of thing.
While I was writing this, I realized something else.  We may want to
change the to_torch and to_tensorflow methods to accept device and
stream arguments, and do the channel and layout shuffling on the GPU
instead of the CPU.  This wouldn't require us to natively support CUDA
or anything like that; we'd just be using PyTorch / TensorFlow's
existing CUDA support, which is easy.

This demo still (as before) shows the GPU-focused way to do the
channel and layout shuffling, presented as an alternative to using
to_torch.  A quick test shows about 107 ms / frame (to_torch)
vs. about 62 ms / frame (GPU-focused routine), and that's including
the CNN itself too.  So there's a very significant benefit there.
(That's not quite a fair comparison, since the GPU-focused routine is
exactly what this program needs, but not so it'd be a big difference.)
While improving performance earlier in this PR, I had introduced a
case where to_torch would fail only for the RGB order.  It also seemed
likely that some cases might fail only if using particular
combinations of channel order and layout, so we just test them all.
This adds a device= flag to to_torch, so the user can specify the
destination device.  (TensorFlow has more automatic device management,
and we don't need to do anything explicit.)

We also do all the channel shuffling to the GPU.  For cases when
channel shuffling or dtype conversion requires a copy, this is immensely
faster than the alternative.

I ran a rough test with the cat detector on my 4k monitor (for
everything, including the CNN inference).  On a GPU, there's a
significant performance boost.  However, this is now slower when run
on the CPU.

* Old code, with GPU: 99 ms/frame
* New code, with GPU: 56 ms/frame
* Old code, no GPU: 3164 ms/frame
* New code, no GPU: 3219 ms/frame
* New code, running to_torch(device="cpu") and and then transferring
  to the GPU for inference: 117 ms/frame

It seems the new to_torch is slower when running on the CPU.  I
suspect (but this is a loose guess) that NumPy, which always did the
channel shuffles in the old code, was faster at that.  It might also
be specific to the extra copy that I think this change introduces in
the RGB CHW conversion path in this, due to PyTorch limitations.

I don't think this is a significant problem: PyTorch and TensorFlow
users are almost all going to be using GPUs.  I will still look at
ways to improve the CPU performance on PyTorch, though.
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

ScreenShot gains four new conversion methods (to_pil, to_numpy, to_torch, to_tensorflow) with Channels/Layout type literals and memoryview[int] re-typing. Demo scripts, doc examples, and usage.rst are updated to use these methods. A new third-party test suite covers all four conversions. CI matrix switches from emoji-based to name-based OS selection.

Changes

ScreenShot Framework Conversion API

Layer / File(s) Summary
ScreenShot types and conversion methods
src/mss/screenshot.py
Defines Channels/Layout literals, re-types _raw to memoryview[int], and implements to_pil, to_numpy, to_torch, and to_tensorflow with channel reordering, layout transposition, dtype casting, and float scaling.
Third-party test suite
src/tests/third_party/conftest.py, src/tests/third_party/test_*_method.py, src/tests/test_setup.py
Adds framework_test_image fixture and reordered_test_image helper; adds per-framework test modules verifying shape, dtype, channel ordering, layout permutations, and error handling for all four methods.
Demo scripts updated to new API
demos/cat-detector.py, demos/tinytv-stream*.py, demos/video-capture*.py
Replaces PIL.Image.frombuffer, manual np.frombuffer+reshape, and pil_to_tensor calls with to_pil, to_numpy, and to_torch; removes the screenshot_to_tensor helper.
Documentation and Sphinx config
docs/source/conf.py, docs/source/usage.rst, docs/source/examples.rst, docs/source/examples/*, docs/source/release-history/v11.0.0.md, src/mss/base.py
Expands intersphinx_mapping; adds usage.rst sections for capturing, pixel data, NumPy array interface, alpha channel, and memory sharing; updates example scripts and .rst references to use the new methods; refreshes docstrings.
CI matrix
.github/workflows/tests.yml
Replaces emoji-keyed OS matrix with name/runs-on entries and updates conditional install/test steps to branch on matrix.os.name.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 Hop, hop, the screenshots leap,
No more frombuffer calls to keep!
to_pil, to_torch, to_numpy too,
TensorFlow joins the conversion queue.
The rabbit cheers with typed delight—
memoryview[int] feels just right! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 48.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding convenience export methods to ScreenShot.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-array-library-methods

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jholveck

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/tests/third_party/test_numpy_method.py (1)

61-67: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add one dtype case for to_numpy().

This suite never exercises the new cast/scale branch in src/mss/screenshot.py Lines 266-270, so regressions in dtype=np.float32 normalization would slip through even though the Torch and TensorFlow variants are covered.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tests/third_party/test_numpy_method.py` around lines 61 - 67, Add a test
case in test_to_numpy_permutations or a nearby dedicated test that calls
ScreenShot.to_numpy with dtype=np.float32 so the cast/scale branch in screenshot
conversion is exercised. Use the existing test helpers like framework_test_image
and reordered_test_image, and assert the float32 output matches the expected
normalized values for one representative channels/layout combination. Keep the
current permutation coverage intact and extend it with one dtype assertion to
catch regressions in to_numpy.
docs/source/conf.py (1)

99-103: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Pin the TensorFlow inventory to an immutable source.

This mapping now follows a community raw/master URL, so doc builds can change or break when that branch moves even if this repo does not. Please pin it to a specific commit/tag or vendor the .inv file into the docs tree.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/source/conf.py` around lines 99 - 103, The TensorFlow InterSphinx
mapping in conf.py is using a mutable raw/master inventory URL, which can make
docs builds unstable. Update the tensorflow entry in the intersphinx mapping to
use an immutable source such as a pinned commit/tag URL, or vendor the
tf2_py_objects.inv file into the docs tree and reference that local copy.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/source/examples/pil_pixels.py`:
- Line 14: The example in the pil_pixels flow is mixing two conversion paths:
img is already created via sct_img.to_pil("RGB"), but the later manual
rebuilding from sct_img.bgra duplicates the conversion and makes the example
unclear. Update the example to use only one path by either keeping the manual
Image.new plus putdata approach throughout or removing the manual pixel
reconstruction and relying on the existing img variable; check the pil_pixels
example flow around the sct_img.to_pil and Image.new/putdata steps.

In `@docs/source/release-history/v11.0.0.md`:
- Around line 22-23: Fix the typo in the release note text by updating the word
“noticible” to “noticeable” in the v11.0.0 documentation entry. The change is in
the release-history markdown content describing memoryview screenshot data, so
just correct that misspelling in the relevant sentence.

In `@docs/source/usage.rst`:
- Around line 109-110: The OpenCV channel-order note is incorrect in the usage
docs and conflicts with the example and surrounding text. Update the wording in
the relevant docs paragraph to refer to BGR/BGRA instead of RGB, and if
appropriate point readers to mss.ScreenShot.to_numpy with channels="BGR" for
OpenCV use.

In `@src/tests/third_party/conftest.py`:
- Line 14: The conftest-level numpy import guard is skipping the entire
src/tests/third_party subtree, including PIL-only tests that should still run
without NumPy. Remove the pytest.importorskip("numpy") from conftest.py and move
the guard into the specific NumPy-dependent helpers or test modules that
actually require np, so PIL-only files like test_pil.py and test_pil_method.py
remain discoverable.

In `@src/tests/third_party/test_torch_method.py`:
- Around line 20-24: The test in shot.to_torch() is hardcoding torch.float32
even though the method defaults to torch.get_default_dtype() when dtype is
omitted. Update the assertion to compare against the current default dtype, or
make the call explicit by passing dtype=torch.float32, so the expectation stays
aligned with the behavior of to_torch().

---

Nitpick comments:
In `@docs/source/conf.py`:
- Around line 99-103: The TensorFlow InterSphinx mapping in conf.py is using a
mutable raw/master inventory URL, which can make docs builds unstable. Update
the tensorflow entry in the intersphinx mapping to use an immutable source such
as a pinned commit/tag URL, or vendor the tf2_py_objects.inv file into the docs
tree and reference that local copy.

In `@src/tests/third_party/test_numpy_method.py`:
- Around line 61-67: Add a test case in test_to_numpy_permutations or a nearby
dedicated test that calls ScreenShot.to_numpy with dtype=np.float32 so the
cast/scale branch in screenshot conversion is exercised. Use the existing test
helpers like framework_test_image and reordered_test_image, and assert the
float32 output matches the expected normalized values for one representative
channels/layout combination. Keep the current permutation coverage intact and
extend it with one dtype assertion to catch regressions in to_numpy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7720f49c-2ffa-4462-bfbd-876a9682742a

📥 Commits

Reviewing files that changed from the base of the PR and between 68bb36c and 706ea74.

📒 Files selected for processing (21)
  • .github/workflows/tests.yml
  • demos/cat-detector.py
  • demos/tinytv-stream-simple.py
  • demos/tinytv-stream.py
  • demos/video-capture-simple.py
  • demos/video-capture.py
  • docs/source/conf.py
  • docs/source/examples.rst
  • docs/source/examples/opencv_numpy.py
  • docs/source/examples/pil.py
  • docs/source/examples/pil_pixels.py
  • docs/source/release-history/v11.0.0.md
  • docs/source/usage.rst
  • src/mss/base.py
  • src/mss/screenshot.py
  • src/tests/test_setup.py
  • src/tests/third_party/conftest.py
  • src/tests/third_party/test_numpy_method.py
  • src/tests/third_party/test_pil_method.py
  • src/tests/third_party/test_tensorflow_method.py
  • src/tests/third_party/test_torch_method.py


# Create an Image
img = Image.new("RGB", sct_img.size)
img = sct_img.to_pil("RGB")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Keep this example on one conversion path.

img is already populated here, but the example still starts rebuilding RGB tuples from sct_img.bgra at Line 17. That makes the script do the conversion twice and muddies the point of a “pixels” example. Either keep the manual Image.new(...)+putdata(...) flow, or drop the manual pixel reconstruction below.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/source/examples/pil_pixels.py` at line 14, The example in the pil_pixels
flow is mixing two conversion paths: img is already created via
sct_img.to_pil("RGB"), but the later manual rebuilding from sct_img.bgra
duplicates the conversion and makes the example unclear. Update the example to
use only one path by either keeping the manual Image.new plus putdata approach
throughout or removing the manual pixel reconstruction and relying on the
existing img variable; check the pil_pixels example flow around the
sct_img.to_pil and Image.new/putdata steps.

Comment on lines +22 to +23
{py:class}`memoryview` objects, rather than {py:class}`bytes` or {py:class}`bytearray` objects. For practical use
cases, this should not be noticible. This change allows faster access to screenshot data, with fewer memory copies.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the typo in this release note.

noticible should be noticeable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/source/release-history/v11.0.0.md` around lines 22 - 23, Fix the typo in
the release note text by updating the word “noticible” to “noticeable” in the
v11.0.0 documentation entry. The change is in the release-history markdown
content describing memoryview screenshot data, so just correct that misspelling
in the relevant sentence.

Comment thread docs/source/usage.rst
Comment on lines +109 to +110
Note that OpenCV uses RGB order, rather than the BGRA order used in this automatic conversion. You may prefer to
use the :py:meth:`mss.ScreenShot.to_numpy` method instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== docs/source/usage.rst (around lines 90-125) ==\n'
sed -n '90,125p' docs/source/usage.rst | cat -n

printf '\n== docs/source/examples.rst (around lines 140-165) ==\n'
sed -n '140,165p' docs/source/examples.rst | cat -n

printf '\n== Search for to_numpy and channels docs ==\n'
rg -n "to_numpy|channels=\"BGR\"|OpenCV|BGRA|RGB order|BGR order" docs/source mss -S

Repository: jholveck/python-mss

Length of output: 6047


Fix the OpenCV channel-order note.
docs/source/usage.rst says OpenCV uses RGB order, but the rest of the docs and the OpenCV example use BGR/BGRA. Update this to BGR/BGRA, or point readers to to_numpy(channels="BGR") for OpenCV.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/source/usage.rst` around lines 109 - 110, The OpenCV channel-order note
is incorrect in the usage docs and conflicts with the example and surrounding
text. Update the wording in the relevant docs paragraph to refer to BGR/BGRA
instead of RGB, and if appropriate point readers to mss.ScreenShot.to_numpy with
channels="BGR" for OpenCV use.

# importorskip), but type checkers don't always know about importorskip.
import numpy as np_typehints # noqa: ICN001

np = pytest.importorskip("numpy")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f . src/tests/third_party | sort
echo
rg -n "importorskip\\(|reordered_test_image|framework_test_image" src/tests/third_party

Repository: jholveck/python-mss

Length of output: 3405


Don't gate src/tests/third_party on NumPy. pytest.importorskip("numpy") in conftest.py skips collection for the whole subtree, so PIL-only tests like test_pil.py and test_pil_method.py disappear in NumPy-free environments. Move the guard into the NumPy-dependent helpers/modules instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tests/third_party/conftest.py` at line 14, The conftest-level numpy
import guard is skipping the entire src/tests/third_party subtree, including
PIL-only tests that should still run without NumPy. Remove the
pytest.importorskip("numpy") from conftest.py and move the guard into the
specific NumPy-dependent helpers or test modules that actually require np, so
PIL-only files like test_pil.py and test_pil_method.py remain discoverable.

Comment on lines +20 to +24
tensor = shot.to_torch()
assert tuple(tensor.shape) == (3, 1, 1)
assert tensor.dtype == torch.float32
expected = torch.tensor([3 / 255.0, 2 / 255.0, 1 / 255.0], dtype=torch.float32)
assert torch.allclose(tensor[:, 0, 0], expected)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n "set_default_dtype|get_default_dtype" src/tests src || true

Repository: jholveck/python-mss

Length of output: 309


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== screenshot implementation =="
sed -n '270,325p' src/mss/screenshot.py

echo
echo "== torch method test =="
sed -n '1,120p' src/tests/third_party/test_torch_method.py

Repository: jholveck/python-mss

Length of output: 5031


Assert against the current default dtype here. to_torch() uses torch.get_default_dtype() when dtype is omitted, so hardcoding torch.float32 makes this test fail if PyTorch’s global default is changed elsewhere. Use torch.get_default_dtype() in the expectation, or pass dtype=torch.float32 explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tests/third_party/test_torch_method.py` around lines 20 - 24, The test in
shot.to_torch() is hardcoding torch.float32 even though the method defaults to
torch.get_default_dtype() when dtype is omitted. Update the assertion to compare
against the current default dtype, or make the call explicit by passing
dtype=torch.float32, so the expectation stays aligned with the behavior of
to_torch().

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds new convenience export methods on mss.ScreenShot to convert screenshots efficiently into common image/ML framework formats (Pillow, NumPy, PyTorch, TensorFlow), along with updated documentation, examples/demos, CI changes, and new third-party tests to validate channel/layout/dtype permutations.

Changes:

  • Add ScreenShot.to_pil(), to_numpy(), to_torch(), and to_tensorflow() with channel/layout/dtype options and related typing.
  • Add third-party test suite for the new export methods (skipping when optional deps aren’t installed) and include them in sdist checks.
  • Update docs/examples/demos and CI to exercise the new pathways and improve framework references.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/mss/screenshot.py Adds new export methods for PIL/NumPy/Torch/TensorFlow and related types/docs.
src/mss/base.py Docstring/reference formatting updates for public API docs.
docs/source/usage.rst Adds usage documentation for capture/pixel access/export/memory sharing.
docs/source/release-history/v11.0.0.md Minor documentation formatting/wording adjustments in release notes.
docs/source/examples/pil.py Updates example to use ScreenShot.to_pil().
docs/source/examples/pil_pixels.py Updates pixel-edit example to use the new PIL conversion path.
docs/source/examples/opencv_numpy.py Updates OpenCV example to use ScreenShot.to_numpy(channels="BGR").
docs/source/examples.rst Updates examples index text and adds guidance around to_numpy() channel choice.
docs/source/conf.py Extends Sphinx intersphinx mappings (numpy/pillow/tf/torch).
demos/video-capture.py Uses to_numpy() in the demo and updates explanatory comments.
demos/video-capture-simple.py Uses to_pil() in the simple video capture demo and trims whitespace.
demos/tinytv-stream.py Uses to_pil() in the TinyTV stream demo.
demos/tinytv-stream-simple.py Uses to_pil() in the TinyTV simple demo.
demos/cat-detector.py Switches the demo to use to_torch() and removes an older helper path.
.github/workflows/tests.yml Installs optional ML deps in CI and adjusts OS selection logic.
src/tests/test_setup.py Ensures new third-party tests are included in sdist contents.
src/tests/third_party/conftest.py Adds shared fixtures/helpers for framework export tests.
src/tests/third_party/test_numpy_method.py Adds tests for ScreenShot.to_numpy() (channels/layout/error cases).
src/tests/third_party/test_pil_method.py Adds tests for ScreenShot.to_pil() (RGB/RGBA and validation).
src/tests/third_party/test_tensorflow_method.py Adds tests for ScreenShot.to_tensorflow() (dtype/layout/channel permutations).
src/tests/third_party/test_torch_method.py Adds tests for ScreenShot.to_torch() (dtype/layout/channel permutations + optional CUDA).
Comments suppressed due to low confidence (1)

docs/source/examples/pil_pixels.py:18

  • This example now creates the image via ScreenShot.to_pil("RGB") and then immediately re-populates it via putdata(). That makes the example slower and more confusing (it no longer demonstrates building an image from pixel data). Either keep Image.new(...)+putdata(...), or keep to_pil() and drop the putdata() path.
    img = sct_img.to_pil("RGB")

    # Best solution: create a list(tuple(R, G, B), ...) for putdata()
    pixels = zip(sct_img.bgra[2::4], sct_img.bgra[1::4], sct_img.bgra[::4], strict=False)
    img.putdata(list(pixels))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +97 to +102
- name: Install PyTorch (Linux CPU)
if: matrix.os.name == 'linux'
run: python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
- name: Install PyTorch (macOS/Windows)
if: matrix.os.name != 'linux'
run: python -m pip install torch
Comment thread src/mss/screenshot.py
else:
msg = 'argument "dtype" must be a torch.dtype'
raise TypeError(msg)
torch_device = torch.get_default_device() if device is None else torch.device(device)
Comment thread docs/source/usage.rst
Comment on lines +109 to +110
Note that OpenCV uses RGB order, rather than the BGRA order used in this automatic conversion. You may prefer to
use the :py:meth:`mss.ScreenShot.to_numpy` method instead.
cases, this should not be noticible. This change allows faster access to screenshot data, with fewer memory
copies.
{py:class}`memoryview` objects, rather than {py:class}`bytes` or {py:class}`bytearray` objects. For practical use
cases, this should not be noticible. This change allows faster access to screenshot data, with fewer memory copies.
@jholveck jholveck closed this Jun 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants