mak47
mak47

Reputation: 303

How do I check the colour of a pixel?

Posting because the posts where this has been fixed are dead and the people maintaining the code haven't replied in months.

Traceback (most recent call last):
  File "c:\Users\Combined_180222_desktop_version .py", line 510, in <module>
    detection()
  File "c:\Users\Combined_180222_desktop_version .py", line 464, in detection
    r,g,b = py.pixel(x, y)
  File "C:\Users\AppData\Local\Programs\Python\Python39\lib\site-packages\pyscreeze\__init__.py", line 614, in pixel
    return (r, g, b)
  File "C:\Users\AppData\Local\Programs\Python\Python39\lib\contextlib.py", line 135, in __exit__
    self.gen.throw(type, value, traceback)
  File "C:\Users\AppData\Local\Programs\Python\Python39\lib\site-packages\pyscreeze\__init__.py", line 123, in __win32_openDC
    raise WindowsError("windll.user32.ReleaseDC failed : return 0")
OSError: windll.user32.ReleaseDC failed : return 0

I'm just trying to check the rgb value of a pixel.

import pyautogui as py

x, y = 1742, 979
r, g, b = py.pixel(x, y)

if b == 106:
    do_something()

When this stopped working I swapped to try and except as described here which worked for about two months but now the error is back.

import pyautogui as py

x, y = 1742, 979
r, g, b = py.pixel(x, y)
        
try:
    if b == 106:
        do_something()
except:
    if b == 106:
        do_somethinge()

I could link another half dozen posts all around the same error. There's a lot of information here about the route of the issue being pixel and pyscreeze being the route of the issue and in this stack Pyautogui and pyscreeze crash with windll.user32.ReleaseDC failed one of the pyscreeze maintainers claims it was fixed back in 0.1.28 yet it's not fixed and I can't seem to find anyone who's doing anything other than talking about it not being fixed.

pip show pyscreeze confirms I'm running 0.1.28 which is meant to contain the fix. Does anyone know how to fix this error?

It might be relevant so I'm posting this next section anyway but may remove it if not relevant to the answer. I am using windll.user32.ReleaseDC elsewhere in a separate class:

import numpy as np
import win32gui, win32ui, win32con

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=None):
        # 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))

        # get the window size
        window_rect = win32gui.GetWindowRect(self.hwnd)
        self.w = window_rect[2] - window_rect[0]
        self.h = window_rect[3] - window_rect[1]

        # account for the window border and titlebar and cut them off
        border_pixels = 0
        titlebar_pixels = 0
        self.w = self.w - (border_pixels * 2)
        self.h = self.h - titlebar_pixels - border_pixels
        self.cropped_x = border_pixels
        self.cropped_y = titlebar_pixels

        # set the cropped coordinates offset so we can translate screenshot
        # images into actual screen positions
        self.offset_x = window_rect[0] + self.cropped_x
        self.offset_y = window_rect[1] + self.cropped_y

    def get_haystack(self):

        # 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())
        img = img[...,:3]
        img = np.ascontiguousarray(img)
        return img

    @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)
    def get_screen_position(self, pos):
        return (pos[0] + self.offset_x, pos[1] + self.offset_y)

Upvotes: 1

Views: 277

Answers (0)

Related Questions