Source code for PIL.ImageGrab

#
# The Python Imaging Library
# $Id$
#
# screen grabber
#
# History:
# 2001-04-26 fl  created
# 2001-09-17 fl  use builtin driver, if present
# 2002-11-19 fl  added grabclipboard support
#
# Copyright (c) 2001-2002 by Secret Labs AB
# Copyright (c) 2001-2002 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#
from __future__ import annotations

import io
import os
import shutil
import subprocess
import sys
import tempfile

from . import Image


[docs] def grab( bbox: tuple[int, int, int, int] | None = None, include_layered_windows: bool = False, all_screens: bool = False, xdisplay: str | None = None, ) -> Image.Image: im: Image.Image if xdisplay is None: if sys.platform == "darwin": fh, filepath = tempfile.mkstemp(".png") os.close(fh) args = ["screencapture"] if bbox: left, top, right, bottom = bbox args += ["-R", f"{left},{top},{right-left},{bottom-top}"] subprocess.call(args + ["-x", filepath]) im = Image.open(filepath) im.load() os.unlink(filepath) if bbox: im_resized = im.resize((right - left, bottom - top)) im.close() return im_resized return im elif sys.platform == "win32": offset, size, data = Image.core.grabscreen_win32( include_layered_windows, all_screens ) im = Image.frombytes( "RGB", size, data, # RGB, 32-bit line padding, origin lower left corner "raw", "BGR", (size[0] * 3 + 3) & -4, -1, ) if bbox: x0, y0 = offset left, top, right, bottom = bbox im = im.crop((left - x0, top - y0, right - x0, bottom - y0)) return im # Cast to Optional[str] needed for Windows and macOS. display_name: str | None = xdisplay try: if not Image.core.HAVE_XCB: msg = "Pillow was built without XCB support" raise OSError(msg) size, data = Image.core.grabscreen_x11(display_name) except OSError: if ( display_name is None and sys.platform not in ("darwin", "win32") and shutil.which("gnome-screenshot") ): fh, filepath = tempfile.mkstemp(".png") os.close(fh) subprocess.call(["gnome-screenshot", "-f", filepath]) im = Image.open(filepath) im.load() os.unlink(filepath) if bbox: im_cropped = im.crop(bbox) im.close() return im_cropped return im else: raise else: im = Image.frombytes("RGB", size, data, "raw", "BGRX", size[0] * 4, 1) if bbox: im = im.crop(bbox) return im
[docs] def grabclipboard() -> Image.Image | list[str] | None: if sys.platform == "darwin": fh, filepath = tempfile.mkstemp(".png") os.close(fh) commands = [ 'set theFile to (open for access POSIX file "' + filepath + '" with write permission)', "try", " write (the clipboard as «class PNGf») to theFile", "end try", "close access theFile", ] script = ["osascript"] for command in commands: script += ["-e", command] subprocess.call(script) im = None if os.stat(filepath).st_size != 0: im = Image.open(filepath) im.load() os.unlink(filepath) return im elif sys.platform == "win32": fmt, data = Image.core.grabclipboard_win32() if fmt == "file": # CF_HDROP import struct o = struct.unpack_from("I", data)[0] if data[16] != 0: files = data[o:].decode("utf-16le").split("\0") else: files = data[o:].decode("mbcs").split("\0") return files[: files.index("")] if isinstance(data, bytes): data = io.BytesIO(data) if fmt == "png": from . import PngImagePlugin return PngImagePlugin.PngImageFile(data) elif fmt == "DIB": from . import BmpImagePlugin return BmpImagePlugin.DibImageFile(data) return None else: if os.getenv("WAYLAND_DISPLAY"): session_type = "wayland" elif os.getenv("DISPLAY"): session_type = "x11" else: # Session type check failed session_type = None if shutil.which("wl-paste") and session_type in ("wayland", None): args = ["wl-paste", "-t", "image"] elif shutil.which("xclip") and session_type in ("x11", None): args = ["xclip", "-selection", "clipboard", "-t", "image/png", "-o"] else: msg = "wl-paste or xclip is required for ImageGrab.grabclipboard() on Linux" raise NotImplementedError(msg) p = subprocess.run(args, capture_output=True) if p.returncode != 0: err = p.stderr for silent_error in [ # wl-paste, when the clipboard is empty b"Nothing is copied", # Ubuntu/Debian wl-paste, when the clipboard is empty b"No selection", # Ubuntu/Debian wl-paste, when an image isn't available b"No suitable type of content copied", # wl-paste or Ubuntu/Debian xclip, when an image isn't available b" not available", # xclip, when an image isn't available b"cannot convert ", # xclip, when the clipboard isn't initialized b"xclip: Error: There is no owner for the ", ]: if silent_error in err: return None msg = f"{args[0]} error" if err: msg += f": {err.strip().decode()}" raise ChildProcessError(msg) data = io.BytesIO(p.stdout) im = Image.open(data) im.load() return im