Search code examples
pythonpathpyautoguipathlib

Failed to read images when folder has special characters on name


Basically I'm using locateOnScreen() function, which is from pyautogui to read an image and then find in the screen by:

import os
import pathlib
import pyautogui

Image = os.path.join(os.path.sep, pathlib.Path(__file__).parent.resolve(), 'static', 'img', 'game', 'image-btn.png')

if pyautogui.locateOnScreen(BossImg, grayscale=True, confidence=0.95) != None:
    print(True)

The code above works prety fine, the problem is when some users, even me because my native language is Portuguese and we have special characters in the language, and we might have some in a folder name.
Let's use this example:

In english:

C:\Users\guilh\Desktop\Folder

In Portuguese:

C:\Users\guilh\Área de Trabalho\Folder

So for some cases when we get a folder with accented characters, I'm getting the error:

Failed to read C:\Users\guilh\Área de Trabalho\Folder\image-btn.png because file is missing, has improper permissions, or is an unsupported or invalid format

But why am I gettig this error with special characters if I'm passing the path correctly with pathlib and os? If I run the same script in the English example, works perfectly.


Solution

  • After digging a bit in the source code of PyAutoGUI on Github, it appears that PyScreeze is used to detect an element on the screen from an image of it, and it uses openCV's imread() function to load the image.

    cv2.imread() currently does not support pathnames containing Non-ASCII characters on Windows.

    A pull-request has already been opened on the PyScreeze repository to use cv2.imdecode() instead of cv2.imread().


    To fix this issue while waiting for the support for non-ASCII characters,

    Method 1

    The first option would be to modify the PyScreeze package installed (This can be annoying if anyone needs to be able to run the script easily from their computer).

    - Identify the location of the PyScreeze module:

    python -c "import pyscreeze; print(pyscreeze.__path__)"
    

    - Modify __init__.py located in this folder:

    Line 21,

    import numpy as np
    

    Line 166,

    img_cv = cv2.imdecode(np.fromfile(img, dtype=np.uint8), LOAD_GRAYSCALE)
    

    Line 168,

    img_cv = cv2.imdecode(np.fromfile(img, dtype=np.uint8), LOAD_COLOR)
    

    - Finally install numpy

    pip install numpy
    

    Method 2

    As @SiP explained, Another possibility could be to copy the image to a temporary folder.

    Something like that:

    import os
    import pathlib
    import tempfile
    import shutil
    import pyautogui
    
    Image = os.path.join(os.path.sep, pathlib.Path(__file__).parent.resolve(), 'static', 'img', 'game', 'image-btn.png')
    temp_path = os.path.join(tempfile.gettempdir(), "file_name_in_ascii")
    shutil.copy2(Image, temp_path)
    
    if pyautogui.locateOnScreen(temp_path, grayscale=True, confidence=0.95) is not None:
        print(True)