From 5fa2e479926a1556fe505bd22c8e48378842f297 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 11 Nov 2021 01:16:18 -0500 Subject: [PATCH 1/4] check before PrintWindow --- src/capture_windows.py | 45 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/capture_windows.py b/src/capture_windows.py index d6798ed6..e2469d93 100644 --- a/src/capture_windows.py +++ b/src/capture_windows.py @@ -1,13 +1,14 @@ from ctypes import windll -from ctypes.wintypes import LONG, RECT +from ctypes.wintypes import LONG, RECT, HBITMAP +from typing import Dict from win32 import win32gui import numpy as np import win32ui import win32con -import numpy as np # This is an undocumented nFlag value for PrintWindow PW_RENDERFULLCONTENT = 0x00000002 +accelerated_windows: Dict[int, bool] = {} def capture_region(hwnd: int, rect: RECT): @@ -20,26 +21,42 @@ def capture_region(hwnd: int, rect: RECT): @return: The image of the region in the window in BGRA format """ + is_accelerated_window = accelerated_windows.get(hwnd) + + # The window type is not yet known, let's find out! + if is_accelerated_window is None: + # We need to get the image at least once to check if it's full black + image = __get_image(hwnd, rect, False) + # TODO check for first non-black pixel, no need to iterate through the whole image + is_accelerated_window = not np.count_nonzero(image) + accelerated_windows[hwnd] = is_accelerated_window + return __get_image(hwnd, rect, True) if is_accelerated_window else image + + return __get_image(hwnd, rect, is_accelerated_window) + + +def __get_image(hwnd: int, rect: RECT, printWindow=False): width: LONG = rect.right - rect.left height: LONG = rect.bottom - rect.top - - windowDC = win32gui.GetWindowDC(hwnd) + windowDC: int = win32gui.GetWindowDC(hwnd) dcObject = win32ui.CreateDCFromHandle(windowDC) + + # Causes a 10-15x performance drop. But allows recording hardware accelerated windows + if (printWindow): + windll.user32.PrintWindow(hwnd, dcObject.GetSafeHdc(), PW_RENDERFULLCONTENT) + compatibleDC = dcObject.CreateCompatibleDC() - bmp = win32ui.CreateBitmap() - bmp.CreateCompatibleBitmap(dcObject, width, height) - compatibleDC.SelectObject(bmp) + bitmap: HBITMAP = win32ui.CreateBitmap() + bitmap.CreateCompatibleBitmap(dcObject, width, height) + compatibleDC.SelectObject(bitmap) compatibleDC.BitBlt((0, 0), (width, height), dcObject, (rect.left, rect.top), win32con.SRCCOPY) - # Force render full content through PrintWindow. Workaround to capture hardware accelerated windows - windll.user32.PrintWindow(hwnd, dcObject.GetSafeHdc(), PW_RENDERFULLCONTENT) - - img: np._BufferType = np.frombuffer(bmp.GetBitmapBits(True), dtype='uint8') - img.shape = (height, width, 4) + image: np._BufferType = np.frombuffer(bitmap.GetBitmapBits(True), dtype='uint8') + image.shape = (height, width, 4) dcObject.DeleteDC() compatibleDC.DeleteDC() win32gui.ReleaseDC(hwnd, windowDC) - win32gui.DeleteObject(bmp.GetHandle()) + win32gui.DeleteObject(bitmap.GetHandle()) - return img + return image From 5a014131f9e46b6d36b99b68fde384470e20de11 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 11 Nov 2021 13:26:20 -0500 Subject: [PATCH 2/4] Check is_windows_11 for PrintWindow --- src/capture_windows.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/capture_windows.py b/src/capture_windows.py index e2469d93..d8065416 100644 --- a/src/capture_windows.py +++ b/src/capture_windows.py @@ -2,6 +2,7 @@ from ctypes.wintypes import LONG, RECT, HBITMAP from typing import Dict from win32 import win32gui +import sys import numpy as np import win32ui import win32con @@ -9,6 +10,7 @@ # This is an undocumented nFlag value for PrintWindow PW_RENDERFULLCONTENT = 0x00000002 accelerated_windows: Dict[int, bool] = {} +is_windows_11 = sys.getwindowsversion().build >= 22000 def capture_region(hwnd: int, rect: RECT): @@ -21,7 +23,9 @@ def capture_region(hwnd: int, rect: RECT): @return: The image of the region in the window in BGRA format """ - is_accelerated_window = accelerated_windows.get(hwnd) + # Windows 11 has some jank, and we're not ready to fully investigate it + # for now let's ensure it works at the cost of performance + is_accelerated_window = is_windows_11 or accelerated_windows.get(hwnd) # The window type is not yet known, let's find out! if is_accelerated_window is None: @@ -35,14 +39,14 @@ def capture_region(hwnd: int, rect: RECT): return __get_image(hwnd, rect, is_accelerated_window) -def __get_image(hwnd: int, rect: RECT, printWindow=False): +def __get_image(hwnd: int, rect: RECT, print_window=False): width: LONG = rect.right - rect.left height: LONG = rect.bottom - rect.top windowDC: int = win32gui.GetWindowDC(hwnd) dcObject = win32ui.CreateDCFromHandle(windowDC) # Causes a 10-15x performance drop. But allows recording hardware accelerated windows - if (printWindow): + if (print_window): windll.user32.PrintWindow(hwnd, dcObject.GetSafeHdc(), PW_RENDERFULLCONTENT) compatibleDC = dcObject.CreateCompatibleDC() From d63f050d707e827a7f023f36d0deeb4ba8d51d85 Mon Sep 17 00:00:00 2001 From: Austin <37423484+Toufool@users.noreply.github.com> Date: Thu, 11 Nov 2021 21:11:47 -0500 Subject: [PATCH 3/4] correct Windows 11 check --- src/capture_windows.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/capture_windows.py b/src/capture_windows.py index d8065416..b0a9c84f 100644 --- a/src/capture_windows.py +++ b/src/capture_windows.py @@ -3,6 +3,8 @@ from typing import Dict from win32 import win32gui import sys +from packaging import version +import platform import numpy as np import win32ui import win32con @@ -10,7 +12,7 @@ # This is an undocumented nFlag value for PrintWindow PW_RENDERFULLCONTENT = 0x00000002 accelerated_windows: Dict[int, bool] = {} -is_windows_11 = sys.getwindowsversion().build >= 22000 +is_windows_11 = version.parse(platform.version()) >= version.parse("10.0.22000") def capture_region(hwnd: int, rect: RECT): From cada37b5d1db0969448af6e6adbc40ca6b7a5964 Mon Sep 17 00:00:00 2001 From: Austin <37423484+Toufool@users.noreply.github.com> Date: Thu, 11 Nov 2021 21:12:18 -0500 Subject: [PATCH 4/4] Change Version to 1.5.2 --- src/about.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about.py b/src/about.py index 93f90bfe..66bd36f1 100644 --- a/src/about.py +++ b/src/about.py @@ -59,7 +59,7 @@ def retranslateUi(self, aboutAutoSplitWidget): aboutAutoSplitWidget.setWindowTitle(_translate("aboutAutoSplitWidget", "About AutoSplit", None)) self.okButton.setText(_translate("aboutAutoSplitWidget", "OK", None)) self.createdbyLabel.setText(_translate("aboutAutoSplitWidget", "

Created by Toufool and Faschz

", None)) - self.versionLabel.setText(_translate("aboutAutoSplitWidget", "Version: 1.5.1", None)) + self.versionLabel.setText(_translate("aboutAutoSplitWidget", "Version: 1.5.2", None)) self.donatetextLabel.setText(_translate("aboutAutoSplitWidget", "If you enjoy using this program, please\n" " consider donating. Thank you!", None)) self.donatebuttonLabel.setText(_translate("aboutAutoSplitWidget", "

", None))