Как выбрать, какой экран ImageGrab.grab () захватывает в настройке нескольких мониторов? - PullRequest
6 голосов
/ 08 февраля 2012

Как видно из названия, мне любопытно, есть ли способ настроить модуль ImageGrab.grab () для захвата, например, правого экрана вместо левого в настройке с несколькими мониторами.

1 Ответ

6 голосов
/ 08 февраля 2012

К сожалению, это невозможно из-за способа, которым PIL получает размеры устройства отображения. Когда он получает контекст устройства, он получает один для всех подключенных мониторов:

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

( display.c , строка 296, версия 1.1.7)

Однако, чтобы получить размеры дисплея, он использует этот код:

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

( display.c , строки 299-300, версия 1.1.7)

Который возвращает только размеры основного активного монитора. Все последующие операции выполняются с этими значениями ширины и высоты, в результате чего получается конечное изображение, размер которого равен только размеру основного дисплея.


Чтобы получить скриншот всех подключенных мониторов, эти две строки необходимо заменить на что-то вроде:

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

После чего вам нужно будет перекомпилировать PIL. Это даст вам размеры виртуального экрана, который является «... ограничивающим прямоугольником всех мониторов дисплея». [ MSDN ]

Более правильной реализацией было бы использование EnumDisplayMonitors для получения контекстов устройства для отдельных мониторов, наряду с изменением интерфейса ImageGrab.grab () (или добавлением новой функции), чтобы позволить выбор конкретный монитор, контекст устройства которого будет использоваться для оставшихся операций.

...