当我们的python GuI在开发时。经常会用到图片作为背景,但是在打包后再启动GUI后却发现:原先调试时好端端的背景图片竟然不翼而飞或者直接报错。这说明图片没有被pyinstaller一起打包……
要解决这个问题很简单,就是更改图片的存储方式。
tkinter设置图片为背景
首先,无论如何,要想导入并在GUI中显示图片,我们都要用到pilllow这个库
pillow获取方式
pip install pillow
正常显示思路
- 使用pillow Image下的open方法读取给定路径下(一般是同级目录,只需要指定文件名)的图片
- 使用pillow的ImageTk(专门用作于tkinter交互的图像处理工具)将其转换为tkinter类型图片
- 在tkinter中创建一个和窗口一样大的canvas将image传入作为背景图片
代码
import tkinter as tk
################################
#使用pillow读取显示图片
from PIL import Image,ImageTk
################################
window_width,window_height=500,300
root=tk.Tk()
image=Image.open('背景.jpg').resize((window_width,window_height))
backgroud_image=ImageTk.PhotoImage(image)
root.title('测试')
root.geometry(f'{window_width}x{window_height}')
main_canvas=tk.Canvas(root,width=window_width,height=window_height)
main_canvas.create_image(0,0,anchor='nw',image=backgroud_image)
main_canvas.pack(fill='both',expand=True)
root.mainloop()
效果:
这是按照上述思路运行代码后的效果,接下来我们使用pyinstaller试着将其打包成一个exe文件
打包方法可以见这篇文章:https://blog.csdn.net/weixin_73953650/article/details/146621947?fromshare=blogdetail&sharetype=blogdetail&sharerId=146621947&sharerefer=PC&sharesource=weixin_73953650&sharefrom=from_linkhttps://blog.csdn.net/weixin_73953650/article/details/146621947?fromshare=blogdetail&sharetype=blogdetail&sharerId=146621947&sharerefer=PC&sharesource=weixin_73953650&sharefrom=from_link
打包后,我们运行该exe文件,报错:
报错原因很简单,就是无法找到背景.jpg这个文件,这是因为pyinstaller只能用来打包py文件
解决思路
解决上述问题的办法很多,但是个人认为最简单的一种便是把图片转换成py文件即可,到这儿有小伙伴可能会问怎么把图片写入到py文件中呢?
嘿嘿,这里我们其实只需要使用base64将图片encode成字符串,便可以实现上述操作,在用的时候将其从存储这个base64字符串的py文件中导入,然后再decode一下成bytes便可正常使用了……
图像转换为base64字符串
import base64
image=open('背景.jpg','rb')
base64_string=base64.b64encode(image.read())
image.close()
print(base64_string)
使用上述几行代码便可以实现将图片转换为base64_string
结果:
将base64字符串写入py文件
写入文件很简单,只需在上述代码中使用open语句完成即可
import base64
image=open('背景.jpg','rb')
base64_string=base64.b64encode(image.read())
image.close()
with open('BackGround.py','w') as py:
py.write(f'img={base64_string}')
结果:
说明:
- 千万不要手贱,随便增删上述结果中的任何一个字符,否则无法转回成图像!
- 在写入的字符串前加了一个img=是为了将其作为py文件中的变量,方便我们使用import调用
从py文件导入base64字符串并转换为图片
import base64
from BackGround import img
from io import BytesIO
from PIL import Image
image=Image.open(BytesIO(base64.b64decode(img)))
运行上述代码后,此时的image便又被转换为原始图像了
结果:
然后,按照最开始正常显示的思路,我们将这个image实例经过ImageTK后再传入给tkinter的控件就可以了。
图片转换base64字符串完整代码
import os
import base64
def convert_image_to_string(image_path:str,py_path):
'''
运行该代码后将在当前目录下生成一
Args:
image_path:图片路径,倘若你的图片与当前py文件同一个文件夹下用名称也可以\n
py_path:输出的python文件路径,可以只是名称比如BackGround.py或者直接传入一个地址\n
'''
#image_path是文件名的时候,路径为当前工作区文件夹+图像名字,否则是图像原始路径,os.path会自动处理这一问题,不需要我们手动判断
image_path=os.path.join(os.curdir,image_path)
#py_path是文件名的时候,路径为当前工作区文件夹+py名字,否则是py文件原始路径,os.path会自动处理这一问题,不需要我们手动判断
py_path=os.path.join(os.curdir,py_path)
print(py_path)
with open(py_path,'w') as py:
image=open(image_path,'rb')
py.write(f'ImageString={base64.b64encode(image.read())}')
image.close()
convert_image_to_string(image_path='背景.jpg',py_path='bg.py')
运行上述代码后,给定image_path路径下的图片将会经过base64编码后在给定的py_path路径下生成一个py文件,py文件的内容是ImageString= 'base64字符串'
结果:
当前工作区文件夹下多了一个bg.py文件,内容是:
base64字符串转换图片完整代码
前边我们已经生成了一个名为bg.py的文件,那么接下来我们只需从bg.py中导入ImageString这个字符串变量,然后将其bas64.bsdecode后经过Bytesio将
import base64
from bg import ImageString#刚刚转换过的base64字符串变量
from io import BytesIO
from PIL import Image,ImageTk
def convert_string_to_image(ImageString:str,size:tuple):
'''
Args:
ImageString:图像的base64字符串变量
size:图像尺寸,(width,height)
'''
image_bytes=base64.b64decode(ImageString)#decode方法返回的是bytes型数据
#pillow的Image下的open方法需要是文件路径或IObytes类型数据
#因此需要使用BytesIO将bytes图像数据转换为io_bytes类型
io_image_bytes=BytesIO(image_bytes)
image=Image.open(io_image_bytes).resize(size)
return image
image=convert_string_to_image(ImageString,size=(500,300))
image
结果:
当然,如果这个图像你是打算用于tkinter控件作为背景,那么还需在函数返回值的前一行添加一个
image=ImageTk.PhotoImage(image)
这样我们就可以愉快地使用了!
测试
我们按照这样的方法来试一下,看看这样将图片作为背景的GUI是否能够在打包后正常显示
GUI完整代码:
import base64
import tkinter as tk
from bg import ImageString#刚刚转换过的base64字符串变量
from io import BytesIO
from PIL import Image,ImageTk
def convert_string_to_image(ImageString:str,size:tuple):
'''
Args:
ImageString:图像的base64字符串变量
size:图像尺寸,(width,height)
'''
image_bytes=base64.b64decode(ImageString)#decode方法返回的是bytes型数据
#pillow的Image下的open方法需要是文件路径或IObytes类型数据
#因此需要使用BytesIO将bytes图像数据转换为io_bytes类型
io_image_bytes=BytesIO(image_bytes)
image=Image.open(io_image_bytes).resize(size)
image=ImageTk.PhotoImage(image)
return image
################################
window_width,window_height=500,300
root=tk.Tk()
root.title('测试')
root.geometry(f'{window_width}x{window_height}')
main_canvas=tk.Canvas(root,width=window_width,height=window_height)
backgroud_image=convert_string_to_image(ImageString,size=(window_width,window_height))
main_canvas.create_image(0,0,anchor='nw',image=backgroud_image)
main_canvas.pack(fill='both',expand=True)
root.mainloop()
结果:
双击运行打包好后的exe文件,没有出现前边所示的错误,正常运行!
总结
以上便是解决pyinstallerGUI打包时无法打包图片问题的所有内容,如果对你有用,免费的赞和收藏来一波支持作者😁😁