3

I am using pyautogui in python for the screenshots

import pyautogui
screen = pyautogui.screenshot()
screen.save("file.jpg")

It works fine on a single screen on all platforms. But in a multiscreen system, it combines the two screens in a single screenshot. but I want a screenshot of a monitor which one is currently on use.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Sammu Sundar
  • 556
  • 3
  • 9
  • 24
  • 1
    There is an optional `region` parameter. Together with [some screen info](https://stackoverflow.com/questions/3129322/how-do-i-get-monitor-resolution-in-python), you should be able to achieve what you want. Be aware that position can be negative for some screens. – Thomas Weller Sep 04 '20 at 08:36

3 Answers3

7

mss package can easily solve this problem

1. Install the package

pip install mss

2. Take screenshots

First Monitor

import os
import os.path

import mss


def on_exists(fname):
    # type: (str) -> None
    """
    Callback example when we try to overwrite an existing screenshot.
    """

    if os.path.isfile(fname):
        newfile = fname + ".old"
        print("{} -> {}".format(fname, newfile))
        os.rename(fname, newfile)


with mss.mss() as sct:
    filename = sct.shot(output="mon-{mon}.png", callback=on_exists)
    print(filename)

Second Monitor

import mss
import mss.tools


with mss.mss() as sct:
    # Get information of monitor 2
    monitor_number = 2
    mon = sct.monitors[monitor_number]

    # The screen part to capture
    monitor = {
        "top": mon["top"],
        "left": mon["left"],
        "width": mon["width"],
        "height": mon["height"],
        "mon": monitor_number,
    }
    output = "sct-mon{mon}_{top}x{left}_{width}x{height}.png".format(**monitor)

    # Grab the data
    sct_img = sct.grab(monitor)

    # Save to the picture file
    mss.tools.to_png(sct_img.rgb, sct_img.size, output=output)
    print(output)

Use with OpenCV

import mss
import cv2
import numpy as np

with mss.mss() as sct:
    
    # Get information of monitor 2
    monitor_number = 2
    mon = sct.monitors[monitor_number]

    # The screen part to capture
    monitor = {
        "top": mon["top"],
        "left": mon["left"],
        "width": mon["width"],
        "height": mon["height"],
        "mon": monitor_number,
    }
    output = "sct-mon{mon}_{top}x{left}_{width}x{height}.png".format(**monitor)

    # Grab the data
    sct_img = sct.grab(monitor)
    img = np.array(sct.grab(monitor)) # BGR Image
    
    # Display the picture
    cv2.imshow("OpenCV", img)
    cv2.waitKey(0)

3. Important Notes

  • sct.monitors will contain more than one item even if you have a single monitor because the first item will be the combined screens
>>> sct.monitors # if we have a single monitor
[{'left': 0, 'top': 0, 'width': 1366, 'height': 768}, 
{'left': 0, 'top': 0, 'width': 1366, 'height': 768}]
>>> sct.monitors # if we have two monitors
[{'left': 0, 'top': 0, 'width': 3286, 'height': 1080}, 
{'left': 1920, 'top': 0, 'width': 1366, 'height': 768}, 
{'left': 0, 'top': 0, 'width': 1920, 'height': 1080}]
Karim Elgazar
  • 164
  • 3
  • 4
  • Your important note is gold. I was so confused why there were two list entries when I only had one monitor connected. +1, my man. – Mr.Zeus Aug 10 '23 at 00:14
5

found an solution here!

from PIL import ImageGrab
from functools import partial
ImageGrab.grab = partial(ImageGrab.grab, all_screens=True)

pyautogui.screenshot() will capture all screens.

Qian Zhou
  • 51
  • 1
  • 3
4

If you visit the official documentation website of you will see this :

Q: Does PyAutoGUI work on multi-monitor setups.

A: No, right now PyAutoGUI only handles the primary monitor.

You can use the mss module for this purpose.

from mss import mss
#One screenshot per monitor:

for filename in screenshotter.save():
    print(filename)

#Screenshot of the monitor 1:

for filename in screenshotter.save(screen=1):
    print(filename)

#Screenshot of the monitor 1, with callback:

def on_exists(fname):
    ''' Callback example when we try to overwrite an existing
        screenshot.
    '''
    from os import rename
    from os.path import isfile
    if isfile(fname):
        newfile = fname + '.old'
        print('{0} -> {1}'.format(fname, newfile))
        rename(fname, newfile)
    return True

for filename in screenshotter.save(screen=1, callback=on_exists):
    print(filename)

#A screenshot to grab them all:

for filename in screenshotter.save(output='fullscreen-shot.png', screen=-1):
    print(filename)
PG11
  • 155
  • 5