11

I am attempting to take fast screenshots ready for processing with PIL/Numpy (~0.01s per screenshot) with Python 3.6. Ideally the window would not need to be in the foreground, i.e. even when another window is covering it, the screenshot is still successful.

So far I've modified the code for python 3 from this question: Python Screenshot of inactive window PrintWindow + win32gui

However, all it gets is black images.

import win32gui
import win32ui
from ctypes import windll
from PIL import Image

hwnd = win32gui.FindWindow(None, 'Calculator')

# Get window bounds
left, top, right, bot = win32gui.GetWindowRect(hwnd)
w = right - left
h = bot - top

hwndDC = win32gui.GetWindowDC(hwnd)
mfcDC = win32ui.CreateDCFromHandle(hwndDC)
saveDC = mfcDC.CreateCompatibleDC()

saveBitMap = win32ui.CreateBitmap()
saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)

saveDC.SelectObject(saveBitMap)

result = windll.user32.PrintWindow(hwnd, saveDC.GetSafeHdc(), 1)
print(result)

bmp_info = saveBitMap.GetInfo()
bmp_str = saveBitMap.GetBitmapBits(True)
print(bmp_str)

im = Image.frombuffer(
    'RGB',
    (bmp_info['bmWidth'], bmp_info['bmHeight']),
    bmp_str, 'raw', 'BGRX', 0, 1)

win32gui.DeleteObject(saveBitMap.GetHandle())
saveDC.DeleteDC()
mfcDC.DeleteDC()
win32gui.ReleaseDC(hwnd, hwndDC)

if result == 1:
    im.save("screenshot.png")
kainev
  • 265
  • 2
  • 8
  • In Windows 10, calculator is a store app, not a native Win32 app, so this method won't work. You have to make sure the target app is in forground (`SetForegroundWindow`) then take a screen shot of the whole window, at the specific coordinates of calculator app. – Barmak Shemirani Dec 08 '18 at 10:46
  • I get a black screenshot for any window, not just calculator, and the idea is to capture the contents of windows that aren't in the foreground. – kainev Dec 10 '18 at 15:31

2 Answers2

9

This code worked for me with applications in background, not minimized.

import win32gui
import win32ui

def background_screenshot(hwnd, width, height):
    wDC = win32gui.GetWindowDC(hwnd)
    dcObj=win32ui.CreateDCFromHandle(wDC)
    cDC=dcObj.CreateCompatibleDC()
    dataBitMap = win32ui.CreateBitmap()
    dataBitMap.CreateCompatibleBitmap(dcObj, width, height)
    cDC.SelectObject(dataBitMap)
    cDC.BitBlt((0,0),(width, height) , dcObj, (0,0), win32con.SRCCOPY)
    dataBitMap.SaveBitmapFile(cDC, 'screenshot.bmp')
    dcObj.DeleteDC()
    cDC.DeleteDC()
    win32gui.ReleaseDC(hwnd, wDC)
    win32gui.DeleteObject(dataBitMap.GetHandle())

hwnd = win32gui.FindWindow(None, windowname)
background_screenshot(hwnd, 1280, 780)
Alexandre Calil
  • 121
  • 1
  • 4
0

One possible cause of black screenshots can be running your script as a non-elevated user while trying to take screenshot of an elevated program, i.e. program that is run as admin.

Running your script as admin could, potentially, solve your problem.

ajkula11
  • 21
  • 3