In the meantime I have read a lot of articles about the topic Pysintaller and the embedding of images in an exe. The function resource_path
was for most the solution for the problem. Furthermore there is the possibility to adjust the .spec
file with a.datas =[(.....)]
and apply pyinstaller .spec
again. I got my previous information from this page.
My problem with this, unfortunately, is that applying the resource_path
function works wonderfully on Windows, but doesn't help me on Linux. Unfortunately, the image I want to include does not appear here. I also do not get an error message. Now I have adjusted my .spec
file as described in the article. If I apply Pysintaller .spec
, then I get the message "completed successfully", however the exe cannot be opened any more.
Now I have two suspicions. Either I have configured the spec incorrectly or there are problems loading the image.
import os, sys
import tkinter as tk
from PIL import Image, ImageTk
class pseudo_example:
def __init__(self):
self.root = tk.Tk()
self.root.geometry("600x300")
self.root.title("About-Dialog")
self.root.minsize(480, 210)
self.root.grid_rowconfigure(0, weight=1)
self.root.grid_columnconfigure(0, weight=1)
def resource_path(self,relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
def About(self):
# variable for the grid position
grid_position = 1
try:
photo = tk.Text(self.root, height=10, width=50)
path = self.resource_path("my_image.png")
# I suspect that the following part is the source of the error
self.image = Image.open(path)
# Resize the image in the given (width, height)
self.img = self.image.resize((405, 152))
# Conver the image in TkImage
self.my_img = ImageTk.PhotoImage(self.img)
# the following would be the alternative
# self.my_img = tk.PhotoImage(file=path)
# self.my_img = tk.PhotoImage(file=path)
# self.my_img = self.my_img.zoom(10)
# self.my_img = self.my_img.subsample(20)
photo.insert("end", '\n')
photo.image_create("end", image=self.my_img)
photo.config(state="disable")
photo.grid(column=1, row=0, sticky="w")
except FileNotFoundError:
grid_position = 0
self.root.minsize(240, 200)
about = "About-Dialog"
about_out = tk.Text(self.root, height=10, width=30)
about_out.grid(column=0, row=0, sticky="w")
about_out.insert("end", about)
about_out.config(state="disable")
ok_bu = tk.Button(self.root, text="okay", command=lambda: self.root.destroy())
ok_bu.grid(column=0, row=1, columnspan=grid_position 1, sticky="nswe")
self.root.mainloop()
if __name__ == '__main__':
try:
gui = pseudo_example()
gui.About()
except KeyboardInterrupt:
print("Interrupted")
sys.exit()
my .spec:
block_cipher = None
a = Analysis(['my_file.py'],
pathex=['my_path'],
binaries=[],
datas=[('my_images.png', 'img')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
a.datas = [('my_image.png', 'my_path/my_image.png', 'DATA')]
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='my_file',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
image = 'my_path/my_image.png' )
EDIT:
Now I have noticed the following phenomena. If I include an image via tk.PhotoImage(file=path)
and use Pyinstaller, then I cannot run the exe. However, if I then adjust my .spec as described above, then the exe works beautifully.
But now I have the problem, that I like to use
self.image = Image.open(path)
self.img = self.image.resize((405, 152))
self.my_img = ImageTk.PhotoImage(self.img)
because I want to resize the image. If I enter pyinstaller --onefile --add-data "my_image.png:img" my_file.py
, then I can run the exe, but the image does not appear. So as described above, when I customize .spec
, the app no longer opens.
Consequently, I conclude that to use ImageTk.PhotoImage(self.img)
I still need some imports or do some special customization. Something similar was described here, but unfortunately it doesn't help me.
The whole problem could be worked around by using tk.PhotoImage(file=path)
, however I actually don't want to edit the .spec
file
CodePudding user response:
I finally found a solution. The problem why I couldn't run the app was that the path to the images for the tk.PhotoImage()
case wasn't specified correctly. I simply added base_path=os.path.join(sys._MEIPASS, "img")
to the resource_path
function and now the embedding works for Linux and Windows.
Problem was that Pyinstaller saved the image in an extra folder, so I had to include the new folder in the path.
Here again the code to the function.
def resource_path(self,relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = os.path.join(sys._MEIPASS, "img")
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
A lot of effort for a simple solution :D