I am new to this and I can't figure out which code is correct and fast? All options are working, but then I can’t understand the difference in behavior, please help me figure it out. How does win32gui.ReleaseDC work and is it necessary to use it if everything works without it? Whether to delete objects.
Examples of getting the color of a pixel:
Variant #1
def get_pixel_rgb_color(self, pos: Tuple[int, int]) -> Tuple[int, int, int]:
rect = win32gui.GetWindowRect(self._hwnd)
w = abs(rect[2] - rect[0])
h = abs(rect[3] - rect[1])
hwndDC = win32gui.GetWindowDC(self._hwnd)
mfcDC = win32ui.CreateDCFromHandle(hwndDC)
saveDC = mfcDC.CreateCompatibleDC()
saveBitMap = win32ui.CreateBitmap()
saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
saveDC.SelectObject(saveBitMap)
ret = win32gui.GetPixel(hwndDC, pos[0], pos[1])
r, g, b = ret & 0xFF, (ret >> 8) & 0xFF, (ret >> 16) & 0xFF
return r, g, b
Variant #2
def get_pixel_rgb_color(self, pos: Tuple[int, int]) -> Tuple[int, int, int]:
hwndDC = win32gui.GetWindowDC(self._hwnd)
ret = win32gui.GetPixel(hwndDC, pos[0], pos[1])
r, g, b = ret & 0xFF, (ret >> 8) & 0xFF, (ret >> 16) & 0xFF
return r, g, b
Examples of area screenshot:
Variant #1
def area_screenshot(self, start: Tuple[int, int], size: Tuple[int, int]) -> str:
width, height = size[0], size[1]
x_cord, y_cord = start[0], start[1]
hwnd_dc = win32gui.GetWindowDC(self._hwnd)
mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
dc_obj = mfc_dc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(mfc_dc, width, height)
dc_obj.SelectObject(bmp)
dc_obj.BitBlt(
(0, 0), (width, height), mfc_dc, (x_cord, y_cord), win32con.SRCCOPY
)
signed_ints_arr = bmp.GetBitmapBits(True)
bmp_arr = np.fromstring(signed_ints_arr, dtype=np.uint8)
bmp_info = bmp.GetInfo()
pil_im = Image.frombuffer(
"RGB",
(bmp_info["bmWidth"], bmp_info["bmHeight"]),
bmp_arr,
"raw",
"BGRX",
0,
1,
)
buff = BytesIO()
pil_im.save(buff, format="JPEG")
img_b64 = b64encode(buff.getvalue()).decode("utf-8")
mfc_dc.DeleteDC()
dc_obj.DeleteDC()
win32gui.ReleaseDC(self._hwnd, hwnd_dc)
win32gui.DeleteObject(bmp.GetHandle())
return img_b64
Variant #2
def area_screenshot(self, start: Tuple[int, int], size: Tuple[int, int]) -> str:
width, height = size[0], size[1]
x_cord, y_cord = start[0], start[1]
hwnd_dc = win32gui.GetWindowDC(self._hwnd)
mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
dc_obj = mfc_dc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(mfc_dc, width, height)
dc_obj.SelectObject(bmp)
dc_obj.BitBlt(
(0, 0), (width, height), mfc_dc, (x_cord, y_cord), win32con.SRCCOPY
)
signed_ints_arr = bmp.GetBitmapBits(True)
bmp_arr = np.fromstring(signed_ints_arr, dtype=np.uint8)
bmp_info = bmp.GetInfo()
pil_im = Image.frombuffer(
"RGB",
(bmp_info["bmWidth"], bmp_info["bmHeight"]),
bmp_arr,
"raw",
"BGRX",
0,
1,
)
buff = BytesIO()
pil_im.save(buff, format="JPEG")
img_b64 = b64encode(buff.getvalue()).decode("utf-8")
return img_b64
The official documentation states that ReleaseDC must be called after using GetWindowDC
or GetDC
.
The application must call the
ReleaseDC
function for each call to theGetWindowDC
function and for each call to theGetDC
function that retrieves a common DC.An application cannot use the ReleaseDC function to release a DC that was created by calling the CreateDC function; instead, it must use the
DeleteDC
function. ReleaseDC must be called from the same thread that called GetDC.
If you don't release it, your program will keep occupying this GDI resource, which will cause memory leaks.