This commit is contained in:
Andrew Murray 2026-02-03 21:41:27 +11:00 committed by GitHub
commit 267b16db4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 52 additions and 13 deletions

View File

@ -9,7 +9,7 @@ import pytest
from PIL import Image, ImageGrab
from .helper import assert_image_equal_tofile, skip_unless_feature
from .helper import assert_image_equal_tofile, on_ci, skip_unless_feature
class TestImageGrab:
@ -60,12 +60,44 @@ class TestImageGrab:
ImageGrab.grab(xdisplay="error.test:0.0")
assert str(e.value).startswith("X connection failed")
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
@pytest.mark.skipif(
sys.platform != "darwin" or not on_ci(), reason="Only runs on macOS CI"
)
def test_grab_handle(self) -> None:
p = subprocess.Popen(
[
"osascript",
"-e",
'tell application "Finder"\n'
'open ("/" as POSIX file)\n'
"get id of front window\n"
"end tell",
],
stdout=subprocess.PIPE,
)
stdout = p.stdout
assert stdout is not None
window = int(stdout.read())
ImageGrab.grab(window=window)
im = ImageGrab.grab((0, 0, 10, 10), window=window)
assert im.size == (10, 10)
@pytest.mark.skipif(
sys.platform not in ("darwin", "win32"), reason="macOS and Windows only"
)
def test_grab_invalid_handle(self) -> None:
with pytest.raises(OSError, match="unable to get device context for handle"):
ImageGrab.grab(window=-1)
with pytest.raises(OSError, match="screen grab failed"):
ImageGrab.grab(window=0)
if sys.platform == "darwin":
with pytest.raises(subprocess.CalledProcessError):
ImageGrab.grab(window=-1)
else:
with pytest.raises(
OSError, match="unable to get device context for handle"
):
ImageGrab.grab(window=-1)
with pytest.raises(OSError, match="screen grab failed"):
ImageGrab.grab(window=0)
def test_grabclipboard(self) -> None:
if sys.platform == "darwin":

View File

@ -43,25 +43,29 @@ def grab(
fh, filepath = tempfile.mkstemp(".png")
os.close(fh)
args = ["screencapture"]
if window:
if window is not None:
args += ["-l", str(window)]
elif bbox:
left, top, right, bottom = bbox
args += ["-R", f"{left},{top},{right-left},{bottom-top}"]
subprocess.call(args + ["-x", filepath])
args += ["-x", filepath]
retcode = subprocess.call(args)
if retcode:
raise subprocess.CalledProcessError(retcode, args)
im = Image.open(filepath)
im.load()
os.unlink(filepath)
if bbox:
if window:
if window is not None:
# Determine if the window was in Retina mode or not
# by capturing it without the shadow,
# and checking how different the width is
fh, filepath = tempfile.mkstemp(".png")
os.close(fh)
subprocess.call(
["screencapture", "-l", str(window), "-o", "-x", filepath]
)
args = ["screencapture", "-l", str(window), "-o", "-x", filepath]
retcode = subprocess.call(args)
if retcode:
raise subprocess.CalledProcessError(retcode, args)
with Image.open(filepath) as im_no_shadow:
retina = im.width - im_no_shadow.width > 100
os.unlink(filepath)
@ -125,7 +129,10 @@ def grab(
raise
fh, filepath = tempfile.mkstemp(".png")
os.close(fh)
subprocess.call(args + [filepath])
args.append(filepath)
retcode = subprocess.call(args)
if retcode:
raise subprocess.CalledProcessError(retcode, args)
im = Image.open(filepath)
im.load()
os.unlink(filepath)