Search code examples
pythonwindowswxpythonpyinstaller

Pyinstaller embed images folder in --onefile --windowed application


I am trying to embed a folder with images into generated (with PyInstaller) executable. But it doesn't work for me. Even with one simple image!

The datas variable in my main.spec file looks like this:

datas=[ ('C:\\Users\\<user>\\dir1\\dir2\\MyApp\\images\\*.png', 'images') ],

According to the documentation:

The first string specifies the file or files as they are in this system now. The second specifies the name of the folder to contain the files at run-time.

In the python file I read the image like this:

self.SetIcon(wx.Icon("images\\myicon.png"))

Finally, this is how I package everything in the *.exe using PyInstaller:

pyinstaller --onefile --windowed --icon=images\main32x32.ico main.spec

I am getting the following error:

Failed to load image from file "images\myicon.png"

Could someone tell me what I'm doing wrong?


Solution

  • When you want to embed a file into your executable, you need to do two steps:

    First, add it with add-data to your executable (as you already did). Second, load the file from the extracted path on runtime.

    You are trying to load the file from images/myicon.png, and the path is next to your executable. Still, the file is not there, and meanwhile, the runtime files would be extracted in a temp directory, e.g. C:/Users/<user>/AppData/Local/Temp/_MEIXXX. So it needs to be loaded from that directory.

    You can use sys._MEIPASS to get the temp path where the extracted files are located. Moreover, you can create a function to load external files:

    import os
    import sys
    
    
    def resource_path(relative_path):
        if hasattr(sys, '_MEIPASS'):
            return os.path.join(sys._MEIPASS, relative_path)
        return os.path.join(os.path.abspath("."), relative_path)
    
    
    self.SetIcon(wx.Icon(resource_path("images/myicon.png")))