Thanks to @wchill on Github for finding this solution (link)! Available on Windows, works with hardware acceleration and windows obscured by other windows.
import cv2
import numpy as np
from ctypes import windll
import win32gui
import win32ui
def capture_win_alt(hwnd=None, bmpFileName='hwnd.bmp', jpgFileName='hwnd.png', delete=False,
program_windowTitle='Swapface', program_className='Chrome_WidgetWin_1'):
# Adapted from https://stackoverflow.com/questions/19695214/screenshot-of-inactive-window-printwindow-win32gui
windll.user32.SetProcessDPIAware()
if not hwnd:
hwnd = win32gui.FindWindow(None, program_windowTitle)
# hwnd = win32gui.FindWindowEx(0, 0, program_className, program_windowTitle)
logger.info(f'hwnd: {hwnd}')
if not hwnd:
return None
left, top, right, bottom = win32gui.GetClientRect(hwnd)
w = right - left
h = bottom - top
hwnd_dc = win32gui.GetWindowDC(hwnd)
mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
save_dc = mfc_dc.CreateCompatibleDC()
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(mfc_dc, w, h)
save_dc.SelectObject(bitmap)
# If Special K is running, this number is 3. If not, 1
result = windll.user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), 3)
bmpinfo = bitmap.GetInfo()
bmpstr = bitmap.GetBitmapBits(True)
img = np.frombuffer(bmpstr, dtype=np.uint8).reshape((bmpinfo["bmHeight"], bmpinfo["bmWidth"], 4))
img = np.ascontiguousarray(img)[..., :-1] # make image C_CONTIGUOUS and drop alpha channel
if not result: # result should be 1
win32gui.DeleteObject(bitmap.GetHandle())
save_dc.DeleteDC()
mfc_dc.DeleteDC()
win32gui.ReleaseDC(hwnd, hwnd_dc)
raise RuntimeError(f"Unable to acquire screenshot! Result: {result}")
cv2.imwrite(jpgFileName, img)
return img
def main():
WINDOW_NAME = "Swapface"
while cv2.waitKey(1) != ord('q'):
screenshot = capture_win_alt(program_windowTitle=WINDOW_NAME)
if screenshot is not None:
print(screenshot.shape)
if __name__ == '__main__':
main()