15

I have a python script called main.py that uses some images in the same path, in images folder.

I want to create one exe file that has also the images that are used from main.py script.

myprogram 
|-images_folder 
|-main.py

How I have to do?

I am launching:

pyinstaller --onefile --windowed main.py

But it generates a main.exe that can't visualize the images, because they are not included in exe.

michele
  • 26,348
  • 30
  • 111
  • 168
  • I found this question with answer about the subject: https://stackoverflow.com/questions/7674790/bundling-data-files-with-pyinstaller-onefile – Stef van der Zon Jul 10 '18 at 12:02

3 Answers3

28

To include the images in your .exe file, you need to specify them in a .spec file:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['main.py'],
             pathex=['C:\\Python36\\Scripts'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)

a.datas += [('image.png','path_to_image', "DATA")]

pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)

exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Name of your program',
          debug=False,
          strip=False,
          upx=True,
          console=False)

Save it as main.spec and run it with pyinstaller main.spec Don't forget to replace "image.png" with your actual image file and "path_to_image" with the file path to your image. Also, set pathex= whatever directory your "main.py" file is in.

This will ensure the images are stored within the executable file. To access them, add this fucntion to your main.py file:

import os

def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

Then, every time you would use the file name "image.png", replace it with resource_path("image.png").

ArmindoFlores
  • 483
  • 1
  • 4
  • 8
  • 1
    Lifesaver! I wasted a day following various other posts that didn't work until I found this. Many thanks! – jpmorr Mar 01 '19 at 14:57
  • Bless you. I'm going to add an extra answer detailing my experience, but this should be the accepted answer. – DaveL17 Jan 14 '21 at 15:03
  • Lifesaver indeed. Spent the last two days trying to figure this out! – fishbacp Jun 24 '21 at 13:35
  • Thanks for this! I've spent a day looking for a solution and this is the first to work. The `resource_path()` function was what I was missing. – JBrown Aug 27 '21 at 08:29
11

Just to improve the last answer by Francisco Rodrigues.

    a.datas += [('image.png','path_to_image', "DATA")]

The 'path_to_image' more likely means the image path with "image.png" behind.

Like this:

    a.datas += [('image.png','C:\\User\\user\\Desktop\\image.png', "DATA")]

Instead of :

    a.datas += [('image.png','C:\\User\\user\\Desktop', "DATA")]

or there's an error saying "cannot find " the file.

Book Sun
  • 111
  • 1
  • 4
0

Just adding one more thing I encountered while following the advice from Book Sun and ArmindoFlores - when all your image files are stored in a folder, you have to add that to your relative path.

For example in the python script:

resource_path("image_folder\image.png")

and in the .spec file:

a.datas += [('image_folder\image.png','C:\\User\\user\\Desktop\\image.png', 'DATA')]

This might be obvious to some people but I ran into that error when I tried to implement this solution!