python - PIL ImageGrab 在 VirtualBox 的第二个虚拟监视器上失败

标签 python image screenshot python-imaging-library virtualbox

我设置了一个 VirtualBox 来使用两个显示器。我尝试在第二台显示器上截取一个窗口的屏幕截图:

import ImageGrab
im = ImageGrab.grab(windowrect)
im.save("img.png")

windowrect 我验证了窗口的正确矩形,在本例中为 (1616, 2, 2594, 732)。然而,img.png 只是一个大黑框。任何想法如何解决屏幕抓取和 VirtualBox 之间的这种交互,以便我可以截取第二个虚拟监视器的屏幕截图?

最佳答案

我遇到过同样的问题。如果非要我猜的话,我会假设 ImageGrab 是从 SM_SCREEN 标志获取坐标的,它只给出主显示器的坐标,而不是 SM_VIRTUALSCREEN,它给出整个虚拟屏幕(不过我还没有查看源代码,所以只是猜测)。

也就是说,通过直接与 Windows API 交互,然后将其位图输出转换为更有用的 PIL 对象,很容易解决这个问题。

部分代码:

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)

第一个函数获取屏幕的位图,第二个函数将其转换为 PIL 对象。

如果你不想自己弄清楚其他监视器的坐标,我有一个名为 PyRobot 的小模块。它具有针对特定监视器的功能等等。而且它是纯 Python,所以不需要安装 PyWin32 :)

关于python - PIL ImageGrab 在 VirtualBox 的第二个虚拟监视器上失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3585293/

相关文章:

python - Numba 中的笛卡尔积

python - 如何使用 unittest setUpClass 方法()?

python - NumPy python : Find the highest value from a column for each unique value in another column

javascript - 将 Canvas 中的图像保存在 zip 中

Python:从视频中截取屏幕截图

Python Selenium : running into StaleElementReferenceException

iphone - 使用 OpenGL 在 iPhone 上扭曲图像

CSS 和图像大小

java - 在Android中,是否可以从服务中捕获屏幕截图

ios - Swift:在没有 TabBar 和 NavigationBar 的情况下裁剪屏幕截图