Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 38 additions & 6 deletions Tests/test_imagegrab.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

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:
Expand Down Expand Up @@ -60,12 +60,44 @@ def test_grab_invalid_xdisplay(self) -> None:
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":
Expand Down
21 changes: 14 additions & 7 deletions src/PIL/ImageGrab.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
Loading