asweigart / pyautogui

A cross-platform GUI automation Python module for human beings. Used to programmatically control the mouse & keyboard.
BSD 3-Clause "New" or "Revised" License
10.15k stars 1.23k forks source link

pyautogui.pixel() function does not get the correct pixel values on my iMac #830

Open DataMower opened 9 months ago

DataMower commented 9 months ago

iMac (Retina 5K, 27-inch, Late 2014), Screen Size: 2560 x 1440, resolution is set to standard for monitor macOS Big Sur 11.7.10 MouseInfo 0.1.3 Pillow version 8.0.1 PyAutoGUI version 0.9.52 Digital Color Meter version 5.22

I measure the coordinates of some points on my screen with MouseInfo and get their pixel values with Digital Color Meter. I am working in the Terminal.

pyautogui.pixel() does not return correct pyscreeze.RGB objects (RGB values differ significantly from the ones measured with MousInfo and Digital Color Meter).

What causes this problem and how can I fix it?

I realized that pyautogui.locateOnScreen() does not work either (maybe because of the same problem)

DataMower commented 8 months ago

Luckily, I have found a solution and an explanation for the problem myself :-) pyautogui seems to have difficulties in handling Retina displays of Macs. For example, I have an older iMac model, 5K, 27inch. Native resolution is 5120 x 2880 pixels. The system scales the GUI elements down to make everything fit the 27inch screen, so it reduces the screen size to 2560 x 1440 pixels. To work like it should, you should feed the function pyautogui.pixel() with the native coordinate values not the scaled ones!

Example: let's say I want to get the pixel value of a specific point on my screen:

pyautogui.position()

I get Point(x=675, y=665)

To get the RGB values of that point:

pyautogui.pixel(675*2, 665*2) (the scale factor is 2)

This returns:

RGB(red=214, green=73, blue=207)

I have tested the function and it works! I have noticed that pyautogui.locateOnScreen() has similar difficulties. The coordinates of the returned object are coordinates of the native resolution. That is, to get the effective pixel coordinates that you see on the screen (and that pyautogui.position() reports you) you have to reduce the coordinates by the scale factor!

Example:

I have saved some element of a screenshot (submit.png) and I want pyautogui to locate that element on the screen:

import pyautogui b = pyautogui.locateOnScreen('submit.png')

b holds the following object: Box(left=643, top=745, width=70, height=29)

This element has its top-left corner at (643/2, 745/2) on my screen.

It would be nice if someone could update the source code of pyautogui, I am a novice programmer, unfortunately I don't know how to do that.