使用 Pywin32 截取的屏幕截图有时会出现黑色图像,我认为处理不正确
Screenshots taken with Pywin32 some times get a black imgaes, I think that handle ins't right
def window_full_shot(hwnd, gray=0):
hwnd = get_hwnd(hwnd)[0]
print(hwnd)
print(win32gui.GetClassName(hwnd))
l, t, r, b = win32gui.GetWindowRect(hwnd)
h = b - t
w = r - l
hwindc = win32gui.GetWindowDC(hwnd)
srcdc = win32ui.CreateDCFromHandle(hwindc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, w, h)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (w, h), srcdc, (0, 0), win32con.SRCCOPY)
signedIntsArray = bmp.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (h, w, 4)
print(type(img))
srcdc.DeleteDC()
memdc.DeleteDC()
win32gui.ReleaseDC(hwnd, hwindc)
win32gui.DeleteObject(bmp.GetHandle())
if gray == 0:
return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
else:
return cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
我用这段代码拍了两张windows,一张可以得到正确的img,另一张不行,就这样。
the right code
the bad code
使用electron app、QT、WPF...等框架制作的应用程序将打印黑屏以响应GetDC
或GetWindowDC
。
唯一的办法就是确保目标应用程序可见,并在目标应用程序所在的特定坐标处截取桌面。
Windows GDI 函数通常忽略 alpha 通道。但是,如果您以 32 位检索屏幕截图,则 GetDIBits
会将所有 alpha 值设置为 255(至少在 Windows 10 中)。
关于代码示例(C++),请参考:
Python代码:
import win32gui
import win32ui
import win32con
from ctypes import windll
from PIL import Image
import time
import ctypes
hwnd_target = win32gui.FindWindow(None, 'Calculator') # 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")
def window_full_shot(hwnd, gray=0):
hwnd = get_hwnd(hwnd)[0]
print(hwnd)
print(win32gui.GetClassName(hwnd))
l, t, r, b = win32gui.GetWindowRect(hwnd)
h = b - t
w = r - l
hwindc = win32gui.GetWindowDC(hwnd)
srcdc = win32ui.CreateDCFromHandle(hwindc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, w, h)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (w, h), srcdc, (0, 0), win32con.SRCCOPY)
signedIntsArray = bmp.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (h, w, 4)
print(type(img))
srcdc.DeleteDC()
memdc.DeleteDC()
win32gui.ReleaseDC(hwnd, hwindc)
win32gui.DeleteObject(bmp.GetHandle())
if gray == 0:
return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
else:
return cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
我用这段代码拍了两张windows,一张可以得到正确的img,另一张不行,就这样。 the right code the bad code
使用electron app、QT、WPF...等框架制作的应用程序将打印黑屏以响应GetDC
或GetWindowDC
。
唯一的办法就是确保目标应用程序可见,并在目标应用程序所在的特定坐标处截取桌面。
Windows GDI 函数通常忽略 alpha 通道。但是,如果您以 32 位检索屏幕截图,则 GetDIBits
会将所有 alpha 值设置为 255(至少在 Windows 10 中)。
关于代码示例(C++),请参考:
Python代码:
import win32gui
import win32ui
import win32con
from ctypes import windll
from PIL import Image
import time
import ctypes
hwnd_target = win32gui.FindWindow(None, 'Calculator') # 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")