Python Application cannot find Image(.png) file at Runtime

So I built this python application with a tkinter GUI. I used pyinstaller to convert the .py file into an executable (.exe) file, so that I can send it to non-technical people to use.

When I run the code with these two lines commented out...

root = tk.Tk()
root.title("DOJ Pricing Analyzer")
root.resizable(False,False)
#canvas1 = tk.Canvas(root, width = 350, height = 500, bg = 'white') <-----------This line commented out
#image = ImageTk.PhotoImage( file = "matrix.png" )<--------------This line commented out
canvas1.create_image(0, 0, image = image, anchor = NW)
canvas1.create_text(185,75,fill="white",font="Impact 15 ",

The application runs perfectly when executed (in .exe form in Windows), except the main window is a blank white canvas.

The problem is I need the app to utilize matrix.png so that the UI actually looks cool and not boring.

So after hours of research I tried playing around with the .spec file in many different ways. I thought this would do the trick....(I simply added the matrix.png file to datas), then ran pyinstaller DOJPriceAnalyzer.py --onefile from Powershell

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None


a = Analysis(['DOJPriceAnalyzer.py'],
             pathex=['C:\\Users\\CV7617\\Desktop\\program'],
             binaries=[],
             datas=[('C:\\Users\\CV7617\\Desktop\\program\matrix.png','.')],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='DOJPriceAnalyzer',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True )

But after running the .exe it produced, I am left with this error:


Traceback (most recent call last):
  File "DOJPriceAnalyzer.py", line 16, in <module>
  File "site-packages\PIL\ImageTk.py", line 89, in __init__
  File "site-packages\PIL\ImageTk.py", line 58, in _get_image_from_kw
  File "site-packages\PIL\Image.py", line 2809, in open
FileNotFoundError: [Errno 2] No such file or directory: 'matrix.png'
[3080] Failed to execute script DOJPriceAnalyzer
Exception ignored in: <function PhotoImage.__del__ at 0x0F9F07C8>
Traceback (most recent call last):
  File "site-packages\PIL\ImageTk.py", line 118, in __del__
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'

I've tried many combinations of things (lost count at this point) including this..(modifying .spec files to these, then going through the same motions of running pyinstaller DOJPriceAnalyzer.py --onefile, then running the .exe file)

datas=[(matrix.png','.')],

and

datas=[('C:\\Users\\CV7617\\Desktop\\program','data')],

But these all produce the same error. Any suggestions?


Solution 1:

I think the problem is, you are not keeping a reference to the image. Take a look at this link for an explanation.

To add a permenant reference, just add a line such as

canvas1.im = image

The canvas.create_image docs do mention this

"The image object. This should be a PhotoImage or BitmapImage, or a compatible object (such as the PIL PhotoImage). The application must keep a reference to the image object", but is easy to overlook that!

I don't think this is a specific Pyinstaller issue either. Your approach of adding the image to the datas in the spec file was correct, and that should work OK.

datas = [('matrix.png','.')]

I tried to reproduce your case, with the snippet of code you provided, and I was able to replicate the error and then fix it with this method, so hopefully this will help you too.