Question solved!

PIL.ImageGrab.grab(bbox=None, include_layered_windows=False, all_screens=True)

And it captures every screen.

Answer from Qiasm on Stack Overflow
🌐
GitHub
github.com › python-pillow › Pillow › issues › 1547
ImageGrab fails with multiple monitors · Issue #1547 · python-pillow/Pillow
November 20, 2015 - Also, because my primary monitor is in the middle, the horizontal coordinates for the full virtual desktop go from -1600 to 3519, where 0 is the left-most pixel of my primary monitor. If I try to capture my rightmost monitor using the following code, all I get is a black image: from PIL import ImageGrab img = ImageGrab.grab([1920, 0, 3519, 1199]) img.save("test.jpg")
Author   chilimangoes
🌐
Pillow Documentation
pillow.readthedocs.io › en › stable › reference › ImageGrab.html
ImageGrab module - Pillow (PIL Fork) 12.2.0 documentation
Capture all monitors. Windows OS only. Added in version 6.2.0. ... X11 Display address. Pass None to grab the default system screen. Pass "" to grab the default X11 screen on Windows or macOS. You can check X11 support using PIL.features.check_feature() with feature="xcb".
🌐
Reddit
reddit.com › r/learnpython › pyautogui with multiple monitors
r/learnpython on Reddit: PyAutoGUI with multiple monitors
August 22, 2018 -

Just wondering if anyone else has run into problems using pyautogui.locateCenterOnScreen with multiple monitors and if so, did you find any solution to help the function. I keep getting a None value returned when the image is clearly on the screen.

Thanks

Top answer
1 of 3
6
2 years later UPDATE: The latest version of PIL (v 8.0.1) now supports this, so this solution is no longer needed. Instead add these 3 lines to the top of your code to enable all monitor screengrabs in Windows: from PIL import ImageGrab from functools import partial ImageGrab.grab = partial(ImageGrab.grab, all_screens=True) And then use pyautogui normally. Yes, I solved this problem by using a different screenshot program. Here is my solution, assuming you are using Windows: Save the following in file named "chilimangos.py": #!/usr/bin/env python # -*- coding: utf-8 -*- # chilimangoes.py # from ctypes import windll, c_int, c_uint, c_char_p, c_buffer from struct import calcsize, pack from PIL import Image gdi32 = windll.gdi32 screen_size = (10000, 10000) #optimistic until we know better # Win32 functions CreateDC = gdi32.CreateDCA CreateCompatibleDC = gdi32.CreateCompatibleDC GetDeviceCaps = gdi32.GetDeviceCaps CreateCompatibleBitmap = gdi32.CreateCompatibleBitmap BitBlt = gdi32.BitBlt SelectObject = gdi32.SelectObject GetDIBits = gdi32.GetDIBits DeleteDC = gdi32.DeleteDC DeleteObject = gdi32.DeleteObject # Win32 constants NULL = 0 HORZRES = 8 VERTRES = 10 SRCCOPY = 13369376 HGDI_ERROR = 4294967295 ERROR_INVALID_PARAMETER = 87 #from http://www.math.uiuc.edu/~gfrancis/illimath/windows/aszgard_mini/movpy-2.0.0-py2.4.4/movpy/lib/win32/lib/win32con.py SM_XVIRTUALSCREEN = 76 SM_YVIRTUALSCREEN = 77 SM_CXVIRTUALSCREEN = 78 SM_CYVIRTUALSCREEN = 79 SM_CMONITORS = 80 def grab_screen(region=None): """ Grabs a screenshot. This is a replacement for PIL's ImageGrag.grab() method that supports multiple monitors. (SEE: https://github.com/python-pillow/Pillow/issues/1547) Returns a PIL Image, so PIL library must be installed. param region is in the format (left, top, width, height), which is the same format returned by pyscreeze Usage: im = grab_screen() # grabs a screenshot of all monitors im = grab_screen([0, 0, -1600, 1200]) # grabs a 1600 x 1200 screenshot to the left of the primary monitor im.save('screencap.jpg') """ bitmap = None try: screen = CreateDC(c_char_p('DISPLAY'),NULL,NULL,NULL) screen_copy = CreateCompatibleDC(screen) if region: left,top,width,height = region else: left = windll.user32.GetSystemMetrics(SM_XVIRTUALSCREEN) top = windll.user32.GetSystemMetrics(SM_YVIRTUALSCREEN) width = windll.user32.GetSystemMetrics(SM_CXVIRTUALSCREEN) height = windll.user32.GetSystemMetrics(SM_CYVIRTUALSCREEN) bitmap = CreateCompatibleBitmap(screen, width, height) if bitmap == NULL: print('grab_screen: Error calling CreateCompatibleBitmap. Returned NULL') return hobj = SelectObject(screen_copy, bitmap) if hobj == NULL or hobj == HGDI_ERROR: print('grab_screen: Error calling SelectObject. Returned {0}.'.format(hobj)) return if BitBlt(screen_copy, 0, 0, width, height, screen, left, top, SRCCOPY) == NULL: print('grab_screen: Error calling BitBlt. Returned NULL.') return bitmap_header = pack('LHHHH', calcsize('LHHHH'), width, height, 1, 24) bitmap_buffer = c_buffer(bitmap_header) bitmap_bits = c_buffer(' ' * (height * ((width * 3 + 3) & -4))) got_bits = GetDIBits(screen_copy, bitmap, 0, height, bitmap_bits, bitmap_buffer, 0) if got_bits == NULL or got_bits == ERROR_INVALID_PARAMETER: print('grab_screen: Error calling GetDIBits. Returned {0}.'.format(got_bits)) return image = Image.frombuffer('RGB', (width, height), bitmap_bits, 'raw', 'BGR', (width * 3 + 3) & -4, -1) if not region: #if this was a full screen grab then set the size for future use. global screen_size screen_size = image.size return image finally: if bitmap is not None: if bitmap: DeleteObject(bitmap) DeleteDC(screen_copy) DeleteDC(screen) Then, in your program add this to the pyautogui import: import pyautogui import chilimangoes pyautogui.screenshot = chilimangoes.grab_screen pyautogui.pyscreeze.screenshot = chilimangoes.grab_screen pyautogui.size = lambda: chilimangoes.screen_size
2 of 3
2
I’ve had similar issues. I wrote a gui app on a laptop and had external monitor, but using the locate centre onscreen only found the image if it was on the screen where the icon screenshot was originally taken. I believe it has to do with the screen resolution, so the locate centre on screen command will be looking for an image of a certain size, but if on a different screen then the image is rendered at a different size to what autogui is searching for.
🌐
Reddit
reddit.com › r/learnpython › hacktober opportunity: add multimonitor support to pyautogui for windows
r/learnpython on Reddit: Hacktober opportunity: Add multimonitor support to pyautogui for windows
October 23, 2020 -

I came across a problem today that could be solved by a beginner / intermediate python programmer and a little time. Anyone want to take on a challenge?

The pyautogui.screenshot() function on Windows does not support multiple monitors. This has been a problem for many years, but recently the PIL ImageGrab module (which pyautogui depends on) added the all_screens option.

# primary monitor only 
import pyautogui
im = pyautogui.screenshot() 

# all monitors
from PIL import ImageGrab
im = ImageGrab.grab(all_screens=True)

This new feature just needs to be added to pyautogui / pyscreeze. Easy(ish). You would learn a lot, get listed as a contributor to a popular open source project (great for resumes), and it would count toward a hacktoberfest tshirt!

Here's the issue you would close: https://github.com/asweigart/pyautogui/issues/9

Here's the offending line at the core of what needs to be updated: https://github.com/asweigart/pyscreeze/blob/master/pyscreeze/init.py#L427

🌐
Pillow
pillow.readthedocs.io › en › latest › releasenotes › 6.2.0.html
6.2.0 (2019-10-01) - Pillow (PIL Fork) 12.0.0.dev0 documentation
from PIL import Image, ImageDraw, ImageFont im = Image.new("RGB", (120, 130)) draw = ImageDraw.Draw(im) font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120) draw.text((10, 10), "A", "#f00", font, stroke_width=2, stroke_fill="#0f0") creates the following image: An all_screens argument has been added to ImageGrab.grab. If True, all monitors will be included in the created image.
🌐
PyPI
pypi.org › project › Desktopmagic
Client Challenge
JavaScript is disabled in your browser · Please enable JavaScript to proceed · A required part of this site couldn’t load. This may be due to a browser extension, network issues, or browser settings. Please check your connection, disable any ad blockers, or try using a different browser
🌐
Python
mail.python.org › pipermail › image-sig › 2008-June › 005054.html
[Image-SIG] PIL ImageGrab with multi-monitors.
September 5, 2013 - I have no problem programmatically creating and moving Tkinter windows to any screen, as MS Windows and Tcl/Tk support multiple monitors. Since PIL has been available for years, and multi-monitors are quite common now, I am surprised that the "grab" feature seems to be still limited to one monitor.
Find elsewhere
Top answer
1 of 3
2

I've faced this same issue. If I had to guess, I'd assume that ImageGrab is getting its coordinates from the SM_SCREEN flag, which gives the coordinates of the primary monitor only, rather than the SM_VIRTUALSCREEN, which gives the entire virtual screen (I haven't looked through the source though, so just a guess).

That said, it's easy enough to get around this by interacting directly with the Windows API, then converting its bitmap output into a more usable PIL object.

Some Code:

def _get_screen_buffer(self, bounds=None):
                # Grabs a DC to the entire virtual screen, but only copies to 
                # the bitmap the the rect defined by the user. 

                SM_XVIRTUALSCREEN = 76  # coordinates for the left side of the virtual screen. 
                SM_YVIRTUALSCREEN = 77  # coordinates for the right side of the virtual screen.  
                SM_CXVIRTUALSCREEN = 78 # width of the virtual screen
                SM_CYVIRTUALSCREEN = 79 # height of the virtual screen

                hDesktopWnd = windll.user32.GetDesktopWindow() #Entire virtual Screen

                left = windll.user32.GetSystemMetrics(SM_XVIRTUALSCREEN)
                top = windll.user32.GetSystemMetrics(SM_YVIRTUALSCREEN)
                width = windll.user32.GetSystemMetrics(SM_CXVIRTUALSCREEN)
                height = windll.user32.GetSystemMetrics(SM_CYVIRTUALSCREEN)

                if bounds:
                        left, top, right, bottom = bounds
                        width = right - left 
                        height = bottom - top
                
                hDesktopDC = windll.user32.GetWindowDC(hDesktopWnd)
                if not hDesktopDC: print 'GetDC Failed'; sys.exit()
                
                hCaptureDC = windll.gdi32.CreateCompatibleDC(hDesktopDC)
                if not hCaptureDC: print 'CreateCompatibleBitmap Failed'; sys.exit()

                hCaptureBitmap = windll.gdi32.CreateCompatibleBitmap(hDesktopDC, width, height)
                if not hCaptureBitmap: print 'CreateCompatibleBitmap Failed'; sys.exit()
                
                windll.gdi32.SelectObject(hCaptureDC, hCaptureBitmap)

                SRCCOPY = 0x00CC0020
                windll.gdi32.BitBlt(
                        hCaptureDC, 
                        0, 0, 
                        width, height, 
                        hDesktopDC, 
                        left, top, 
                        0x00CC0020
                )
                return hCaptureBitmap

        def _make_image_from_buffer(self, hCaptureBitmap):
                import Image
                bmp_info = BITMAPINFO()
                bmp_header = BITMAPFILEHEADER()
                hdc = windll.user32.GetDC(None)

                bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER)

                DIB_RGB_COLORS = 0
                windll.gdi32.GetDIBits(hdc, 
                        hCaptureBitmap, 
                        0,0, 
                        None, byref(bmp_info), 
                        DIB_RGB_COLORS
                )

                bmp_info.bmiHeader.biSizeImage = bmp_info.bmiHeader.biWidth *abs(bmp_info.bmiHeader.biHeight) * (bmp_info.bmiHeader.biBitCount+7)/8;
                size = (bmp_info.bmiHeader.biWidth, bmp_info.bmiHeader.biHeight )
                print size
                pBuf = (c_char * bmp_info.bmiHeader.biSizeImage)()

                windll.gdi32.GetBitmapBits(hCaptureBitmap, bmp_info.bmiHeader.biSizeImage, pBuf)

                return Image.frombuffer('RGB', size, pBuf, 'raw', 'BGRX', 0, 1)

The first function gets a bitmap of the screen, and the second guy converts it to a PIL object.

If you don't want to figure out the coordinates of the other monitors yourself, I've got a small module called PyRobot which has functions for targeting specific monitors and whatnot. And it's pure Python, so no need to install PyWin32 :)

2 of 3
0

Audionautics / chriskiehl !

I took your post and some of your library and re-write it for python 3 ! I hope you're okay with it. It works for me using PILLOW (PIL) and the python 3.4 engine.

I just called the file duelMonitory.py containing:

# https://github.com/chriskiehl/pyrobot
# started from Audionautics code on http://stackoverflow.com/questions/3585293/pil-imagegrab-fails-on-2nd-virtual-monitor-of-virtualbox
# updated for PILLOW and Python 3 by Alan Baines (Kizrak)


from PIL import *
#from ctypes import windll, Structure, byref, c_uint
#import ctypes

import ctypes
from ctypes import *
from ctypes.wintypes import *

def get_screen_buffer(bounds=None):
    # Grabs a DC to the entire virtual screen, but only copies to 
    # the bitmap the the rect defined by the user. 

    SM_XVIRTUALSCREEN = 76  # coordinates for the left side of the virtual screen. 
    SM_YVIRTUALSCREEN = 77  # coordinates for the right side of the virtual screen.  
    SM_CXVIRTUALSCREEN = 78 # width of the virtual screen
    SM_CYVIRTUALSCREEN = 79 # height of the virtual screen

    hDesktopWnd = windll.user32.GetDesktopWindow() #Entire virtual Screen

    left = windll.user32.GetSystemMetrics(SM_XVIRTUALSCREEN)
    top = windll.user32.GetSystemMetrics(SM_YVIRTUALSCREEN)
    width = windll.user32.GetSystemMetrics(SM_CXVIRTUALSCREEN)
    height = windll.user32.GetSystemMetrics(SM_CYVIRTUALSCREEN)

    if bounds:
        left, top, right, bottom = bounds
        width = right - left 
        height = bottom - top

    hDesktopDC = windll.user32.GetWindowDC(hDesktopWnd)
    if not hDesktopDC:
        print ('GetDC Failed')
        sys.exit()

    hCaptureDC = windll.gdi32.CreateCompatibleDC(hDesktopDC)
    if not hCaptureDC:
        print ('CreateCompatibleBitmap Failed')
        sys.exit()

    hCaptureBitmap = windll.gdi32.CreateCompatibleBitmap(hDesktopDC, width, height)
    if not hCaptureBitmap:
        print ('CreateCompatibleBitmap Failed')
        sys.exit()

    windll.gdi32.SelectObject(hCaptureDC, hCaptureBitmap)

    SRCCOPY = 0x00CC0020
    windll.gdi32.BitBlt(
        hCaptureDC, 
        0, 0, 
        width, height, 
        hDesktopDC, 
        left, top, 
        0x00CC0020
    )
    return hCaptureBitmap

def make_image_from_buffer(hCaptureBitmap):
    from PIL import Image
    bmp_info = BITMAPINFO()
    bmp_header = BITMAPFILEHEADER()
    hdc = windll.user32.GetDC(None)

    bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER)

    DIB_RGB_COLORS = 0
    windll.gdi32.GetDIBits(hdc, 
        hCaptureBitmap, 
        0,0, 
        None, byref(bmp_info), 
        DIB_RGB_COLORS
    )

    bmp_info.bmiHeader.biSizeImage = int( bmp_info.bmiHeader.biWidth *abs(bmp_info.bmiHeader.biHeight) * (bmp_info.bmiHeader.biBitCount+7)/8 );
    size = (bmp_info.bmiHeader.biWidth, bmp_info.bmiHeader.biHeight )
    print (size)
    pBuf = (c_char * bmp_info.bmiHeader.biSizeImage)()

    windll.gdi32.GetBitmapBits(hCaptureBitmap, bmp_info.bmiHeader.biSizeImage, pBuf)

    return Image.frombuffer('RGB', size, pBuf, 'raw', 'BGRX', 0, 1)


class BITMAPFILEHEADER(ctypes.Structure):
    _fields_ = [
        ('bfType', ctypes.c_short),
        ('bfSize', ctypes.c_uint32),
        ('bfReserved1', ctypes.c_short),
        ('bfReserved2', ctypes.c_short),
        ('bfOffBits', ctypes.c_uint32)
    ]


class BITMAPINFOHEADER(ctypes.Structure):
    _fields_ = [
        ('biSize', ctypes.c_uint32),
        ('biWidth', ctypes.c_int),
        ('biHeight', ctypes.c_int),
        ('biPlanes', ctypes.c_short),
        ('biBitCount', ctypes.c_short),
        ('biCompression', ctypes.c_uint32),
        ('biSizeImage', ctypes.c_uint32),
        ('biXPelsPerMeter', ctypes.c_long),
        ('biYPelsPerMeter', ctypes.c_long),
        ('biClrUsed', ctypes.c_uint32),
        ('biClrImportant', ctypes.c_uint32)
    ]


class BITMAPINFO(ctypes.Structure):
    _fields_ = [
        ('bmiHeader', BITMAPINFOHEADER),
        ('bmiColors', ctypes.c_ulong * 3)
    ]

And my test code was duelMonitor.test.py containing:

from PIL import *

from duelMonitor import *

hCaptureBitmap = get_screen_buffer()

pimage = make_image_from_buffer(hCaptureBitmap)

pimage.save("Hello.png","PNG")

Basically just combination of Audionautics post and his library from https://github.com/chriskiehl/pyrobot webpage and conversion to Python 3 (and PILLOW).

Have fun!

(PS. I would have posted as comment, but I don't have enough points /sadface)

🌐
GitHub
github.com › python-pillow › Pillow › issues › 8120
ImageGrab range error when capturing multi-screen shots and the parameter 'left' is negative · Issue #8120 · python-pillow/Pillow
June 9, 2024 - The issue with multi-monitor screenshot capturing is that when the secondary monitor is positioned to the left of the primary monitor, and in ImageGrab.grab(bbox=(left, top, width, height)), left is set to a negative value like -100, the screenshot will incorrectly include an additional area of 100 pixels (or other lengths) from the right side.
Author   burning-star-x
🌐
GitHub
github.com › python-pillow › Pillow › issues › 7898
ImageGrab.grab() unable to capture screenshot with bounding box coordinates on main screen when external monitor is attached · Issue #7898 · python-pillow/Pillow
March 23, 2024 - However, the code works fine when trying to grab the screenshot in a standalone monitor setup or just capturing external monitor screen. ... from PIL import ImageGrab from io import BytesIO import win32clipboard import win32api import win32con import time def send_to_clipboard(clip_type, data): win32clipboard.OpenClipboard() win32clipboard.EmptyClipboard() win32clipboard.SetClipboardData(clip_type, data) win32clipboard.CloseClipboard() # Screenshot to clipboard def screenshot_to_clipboard(top_left_corner_x, top_left_corner_y, bottom_right_corner_x, bottom_right_corner_y): img = ImageGrab.grab(
Author   rockyko
🌐
GeeksforGeeks
geeksforgeeks.org › python-pil-imagegrab-grab-method
Python PIL | ImageGrab.grab() method - GeeksforGeeks
May 3, 2022 - PIL is the Python Imaging Library ... of the screen or the clipboard to a PIL image memory. PIL.ImageGrab.grab() method takes a snapshot of the screen....
🌐
GitHub
github.com › ludios › Desktopmagic
GitHub - ludios/Desktopmagic: Robust multi-monitor screenshot grabbing library for Python 2.x/3.x on Windows
Desktopmagic can take a screenshot of all monitors. You can: Take a screenshot of the entire virtual screen. Take a screenshot of the entire virtual screen, split into one PIL Image per display. Take a screenshot of just one display. Take a screenshot of an arbitrary region of the virtual screen. ... ImageGrab leaks memory if you try to take a screenshot when the workstation is locked (as of 2011-01).
Starred by 57 users
Forked by 11 users
Languages   Python 100.0% | Python 100.0%
Top answer
1 of 3
10

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}]
2 of 3
7

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.

🌐
Nitratine
nitratine.net › blog › post › how-to-take-a-screenshot-in-python-using-mss
How To Take A Screenshot In Python Using MSS - Nitratine
August 24, 2020 - I only have two monitors, but MSS is advertising all my monitors combined in one shot as the first monitor mss_instance.monitors[0]. This means when you want to screenshot only a monitor by itself, start at 1. Once you identify the display to capture, you can then take the screenshot using mss_instance.grab: from PIL import Image # Will need to make sure PIL is installed import mss with mss.mss() as mss_instance: monitor_1 = mss_instance.monitors[1] screenshot = mss_instance.grab(monitor_1) img = Image.frombytes("RGB", screenshot.size, screenshot.bgra, "raw", "BGRX") # Convert to PIL.Image # Use img as you please
🌐
Lightrun
lightrun.com › answers › asweigart-pyautogui-use-locateonscreen-with-multiple-monitors
Use LocateOnScreen with Multiple Monitors
In my opinion the issue is, that the current version of pyscreeze utilizing ImageGrab (Pillow) on windows only uses single-screen grab. ... enable all_screen grabbing: In file: pyscreeze/__init__.py, function: def _screenshot_win32(imageFilename=None, region=None): change im = ImageGrab.grab() to im = ImageGrab.grab(all_screens= True) handle new introduced negative coordinates due to multiple monitor: In file: pyscreeze/__init__.py, function: def locateOnScreen(image, minSearchTime=0, **kwargs): behind retVal = locate(image, screenshotIm, **kwargs) add
🌐
Nitratine
nitratine.net › blog › post › how-to-take-a-screenshot-in-python-using-pil
How To Take A Screenshot In Python Using PIL - Nitratine
August 24, 2020 - from PIL import ImageGrab screenshot = ImageGrab.grab(all_screens=True) # Take a screenshot that includes all screens · Please note that all_screens is currently only supported in Windows · Now when you call screenshot.show(), you will see that multiple monitors are now displayed.
🌐
GitHub
github.com › python-pillow › Pillow › issues › 6144
ImageGrab.grab(bbox=) fails on Mac with Retina screen, or on secondary monitor · Issue #6144 · python-pillow/Pillow
March 20, 2022 - ImageGrab.grab() is failing to account for the 144 DPI (not 72 DPI "virtual pixels") image generated by screencapture for my Retina display, so the bbox passed to the crop function needs to be scaled by 2 (all 4 parameters). Secondary problem: this all fails completely when the app window is on a secondary monitor.
Author   resnbl
🌐
Fastemailchecker
fastemailchecker.com › gbn69vs › pil-imagegrab-second-monitor
pil imagegrab second monitor
We need PIL library to grab our play area and process it. So, the simple example of position settings is shown bellow The Python Imaging Library uses a coordinate system that starts with (0, 0) in the upper left corner. Book 2 in the Vaults of Terra mini-series. I tried taking a screenshot of a window on the second monitor: import ImageGrab im = ImageGrab.grab (windowrect) im.save (img.png) windowrect I verified to be the correct rect of the window, in this case, (1616, 2, 2594, 732).