Python – How to select which screen ImageGrab.grab() grabs in a multi-monitor setup

pythonpython-imaging-library

Like the title says, I'm curious if there is a way to configure the ImageGrab.grab() module to grab, for instance, the right screen, instead of the left in a multi-monitor setup.

Best Answer

Unfortunately it isn't possible, due to the manner in which the PIL obtains the dimensions of the display device. When it obtains the Device Context, it does obtain one for all attached monitors:

screen = CreateDC("DISPLAY", NULL, NULL, NULL); 

(display.c, line 296, version 1.1.7)

However, to get the display dimensions, it uses this code:

width = GetDeviceCaps(screen, HORZRES);
height = GetDeviceCaps(screen, VERTRES);

(display.c, lines 299-300, version 1.1.7)

Which only returns the dimensions of the primary, active monitor. All subsequent operations are done with these width and height values, resulting in a final image that is only the size of the primary display.


In order to receive a screengrab of all attached monitors, those two lines would need to be replaced with something like:

width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
height = GetSystemMetrics(SM_CYVIRTUALSCREEN);

After which you'd need to recompile PIL. This would provide you with the dimensions of the virtual screen, which is "... the bounding rectangle of all display monitors." [MSDN]

A more correct implementation would be using EnumDisplayMonitors to obtain device contexts for the individual monitors, along with altering ImageGrab.grab()'s interface (or adding a new function) to allow for the selection of a specific monitor, of whose device context would be used for the remaining operations.