import numpy as np import win32con import win32gui import win32ui from config_file import UserConfigs class WindowCapture: # properties w = 0 h = 0 hwnd = None cropped_x = 0 cropped_y = 0 offset_x = 0 offset_y = 0 # constructor def __init__(self, window_name, area, config, coords = 0): # find the handle for the window we want to capture. # if no window name is given, capture the entire screen if window_name is None: self.hwnd = win32gui.GetDesktopWindow() else: self.hwnd = win32gui.FindWindow(None, window_name) if not self.hwnd: raise Exception('Window not found: {}'.format(window_name)) if area == "dig": val = config.returnDiggingWindowPos() elif area == "magic": val = config.returnMagicWindowPos() elif area == "dig2": val = config.returnDiggingWindowPos2() elif area == "equip": val = config.returnEquipmentWindowPos() elif area == "screen_conf": val = config.returnOKWindowPos() elif area == "lanes": val = coords else: val = config.returnFullScreenWindowPos() self.w = val[0] self.h = val[1] self.cropped_x = val[2] self.cropped_y = val[3] def get_screenshot(self, drop_alpha_channel = True): # get the window image data wDC = win32gui.GetWindowDC(self.hwnd) dcObj = win32ui.CreateDCFromHandle(wDC) cDC = dcObj.CreateCompatibleDC() dataBitMap = win32ui.CreateBitmap() dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h) cDC.SelectObject(dataBitMap) cDC.BitBlt((0, 0), (self.w, self.h), dcObj, (self.cropped_x, self.cropped_y), win32con.SRCCOPY) # convert the raw data into a format opencv can read #dataBitMap.SaveBitmapFile(cDC, 'debug.bmp') signedIntsArray = dataBitMap.GetBitmapBits(True) img = np.fromstring(signedIntsArray, dtype='uint8') img.shape = (self.h, self.w, 4) # free resources dcObj.DeleteDC() cDC.DeleteDC() win32gui.ReleaseDC(self.hwnd, wDC) win32gui.DeleteObject(dataBitMap.GetHandle()) # drop the alpha channel, or cv.matchTemplate() will throw an error like: # error: (-215:Assertion failed) (depth == CV_8U || depth == CV_32F) && type == _templ.type() # && _img.dims() <= 2 in function 'cv::matchTemplate' if drop_alpha_channel: img = img[...,:3] # make image C_CONTIGUOUS to avoid errors that look like: # File ... in draw_rectangles # TypeError: an integer is required (got type tuple) # see the discussion here: # https://github.com/opencv/opencv/issues/14866#issuecomment-580207109 img = np.ascontiguousarray(img) return img def get_screenshot_by_area(self, area): w_local = area[0] h_local = area[1] cropped_x_local = area[2] cropped_y_local = area[3] # get the window image data wDC = win32gui.GetWindowDC(self.hwnd) dcObj = win32ui.CreateDCFromHandle(wDC) cDC = dcObj.CreateCompatibleDC() dataBitMap = win32ui.CreateBitmap() dataBitMap.CreateCompatibleBitmap(dcObj, w_local, h_local) cDC.SelectObject(dataBitMap) cDC.BitBlt((0, 0), (w_local, h_local), dcObj, (cropped_x_local, cropped_y_local), win32con.SRCCOPY) # convert the raw data into a format opencv can read #dataBitMap.SaveBitmapFile(cDC, 'debug.bmp') signedIntsArray = dataBitMap.GetBitmapBits(True) img = np.fromstring(signedIntsArray, dtype='uint8') img.shape = (h_local, w_local, 4) # free resources dcObj.DeleteDC() cDC.DeleteDC() win32gui.ReleaseDC(self.hwnd, wDC) win32gui.DeleteObject(dataBitMap.GetHandle()) # drop the alpha channel, or cv.matchTemplate() will throw an error like: # error: (-215:Assertion failed) (depth == CV_8U || depth == CV_32F) && type == _templ.type() # && _img.dims() <= 2 in function 'cv::matchTemplate' img = img[...,:3] # make image C_CONTIGUOUS to avoid errors that look like: # File ... in draw_rectangles # TypeError: an integer is required (got type tuple) # see the discussion here: # https://github.com/opencv/opencv/issues/14866#issuecomment-580207109 img = np.ascontiguousarray(img) return img # find the name of the window you're interested in. # once you have it, update window_capture() # https://stackoverflow.com/questions/55547940/how-to-get-a-list-of-the-name-of-every-open-window @staticmethod def list_window_names(): def winEnumHandler(hwnd, ctx): if win32gui.IsWindowVisible(hwnd): print(hex(hwnd), win32gui.GetWindowText(hwnd)) win32gui.EnumWindows(winEnumHandler, None) # translate a pixel position on a screenshot image to a pixel position on the screen. # pos = (x, y) # WARNING: if you move the window being captured after execution is started, this will # return incorrect coordinates, because the window position is only calculated in # the __init__ constructor. def get_screen_position(self, pos): return (pos[0] + self.offset_x, pos[1] + self.offset_y)