Search code examples
pythonwinapiscreenshotpywin32win32gui

Capturing screenshots with win32api python returns black image


I've used the following code examples to capture a screenshot:

https://stackoverflow.com/a/3260811 https://stackoverflow.com/a/24352388/5858697

When taking a screenshot of Firefox or chrome, they return a blank black image. Capturing a screenshot of notepad works fine. I've done some research on this and I think it's because they're gpu accelerated. Other screenshot libraries work but I need to have it so I can capture a screenshot of an application even if it's not currently visible.

Has anyone solved a similar problem or could someone point me in the right direction? Thank you.


Solution

  • Based on the @Barmak's previous answer, I converted C + + code to python, and now it works.

    import win32gui
    import win32ui
    import win32con
    from ctypes import windll
    from PIL import Image
    import time
    import ctypes
    
    hwnd_target = 0x00480362 #Chrome handle be used for test 
    
    left, top, right, bot = win32gui.GetWindowRect(hwnd_target)
    w = right - left
    h = bot - top
    
    win32gui.SetForegroundWindow(hwnd_target)
    time.sleep(1.0)
    
    hdesktop = win32gui.GetDesktopWindow()
    hwndDC = win32gui.GetWindowDC(hdesktop)
    mfcDC  = win32ui.CreateDCFromHandle(hwndDC)
    saveDC = mfcDC.CreateCompatibleDC()
    
    saveBitMap = win32ui.CreateBitmap()
    saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
    
    saveDC.SelectObject(saveBitMap)
    
    result = saveDC.BitBlt((0, 0), (w, h), mfcDC, (left, top), win32con.SRCCOPY)
    
    bmpinfo = saveBitMap.GetInfo()
    bmpstr = saveBitMap.GetBitmapBits(True)
    
    im = Image.frombuffer(
        'RGB',
        (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
        bmpstr, 'raw', 'BGRX', 0, 1)
    
    win32gui.DeleteObject(saveBitMap.GetHandle())
    saveDC.DeleteDC()
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(hdesktop, hwndDC)
    
    if result == None:
        #PrintWindow Succeeded
        im.save("test.png")
    

    Please note: Firefox uses Windowless Controls.

    If you want to get the handle of Firefox, you may need UI Automation.

    For a detailed explanation, please refer to @IInspectable's answer.