Pyinstaller 和 --onefile:如何在 exe 文件中包含图像

Pyinstaller and --onefile: How to include an image in the exe file

我已经使用 Pyinstaller 创建了一个 exe 文件。

pyinstaller.exe --onefile --icon='Loco.ico program.py

在程序中,我在绘图中包含了一张图像,当我 运行 程序单独放在其文件夹中时,我得到以下信息:

IOError: [Errno 2] No such file or directory: 'Logo.png'

一种解决方案是将图像包含在 exe 的文件夹中,如下面 link 所示:

pyinstaller does not show images and icon

但话又说回来--onefile 的全部要点就是拥有那个,不需要另外的图像。我觉得解决方案可能在这个link,但是我没看懂

Bundling data files with PyInstaller (--onefile)

我的规格文件如下所示:

# -*- mode: python -*-
a = Analysis(['AMOS_Visualizer.py'],
    pathex=['C:\Users\elu\PycharmProjects\Prosjektet\Forsok splitting'],
    hiddenimports=[],
    hookspath=None,
    runtime_hooks=None)

pyz = PYZ(a.pure)
exe = EXE(pyz,
      a.scripts,
      a.binaries,
      a.zipfiles,
      a.datas,
      name='AMOS_Visualizer.exe',
      debug=False,
      strip=None,
      upx=True,
      console=True , icon='AMOS.ico')

编辑:

我相信我找到了解决问题的方法。

# -*- mode: python -*-
a = Analysis(['AMOS_Visualizer.py'],
         pathex=['C:\Users\elu\PycharmProjects\Prosjektet\Forsok splitting'],
         hiddenimports=[],
         hookspath=None,
         runtime_hooks=None)

for d in a.datas:
    if 'pyconfig' in d[0]:
        a.datas.remove(d)
        break

a.datas += [('Logo.png','C:\Users\elu\PycharmProjects\Prosjektet\Forsok splitting\Logo.png', 'Data')]
pyz = PYZ(a.pure)
exe = EXE(pyz,
      a.scripts,
      a.binaries,
      a.zipfiles,
      a.datas,
      name='AMOS_Visualizer.exe',
      debug=False,
      strip=None,
      upx=True,
      console=True, icon='C:\Users\elu\PycharmProjects\Prosjektet\Forsok splitting\AMOS.ico')

并将以下内容添加到我的 main.py 脚本中

def resource_path(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)

Logo = resource_path("Logo.png")

这是以下内容的变体: Bundling data files with PyInstaller (--onefile), 并且给出的答案更清楚。

2 行:

  1. 您必须在 "datas" 中添加图像文件(在您的规范中 文件或使用 PyInstaller 挂钩脚本)
  2. 使用 sys._MEIPASS 如果它 存在,
    使用单行 base_path = getattr(sys, '_MEIPASS', '.')+'/' 得到一个 "root_path" 变量连接到你所有的 文件的路径。
    然后,filepath = base_path + filepath

如果您使用的是 Qt Designer,您可以通过创建一个资源文件并将所有需要的图像(包括 Logo.png)添加到该资源来实现。

要创建资源文件,您可以按照 中的步骤操作。

在资源文件中插入图像后,将Logo.png分配给Window图标,保存QtDesigner界面并使用命令转换资源文件:pyrcc4 -py3 resourcetest.qrc -o resourcetest_rc.py

最后,使用--onefile选项创建exe文件。无需编辑规范文件。

在"hiddenimports = []"之前添加"datas = ['Location of your file'],"。它会做的。 就我而言,这有效

    # -*- mode: python -*-

block_cipher = None


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

我已经尝试了很多,但一个小时后就成功了:

当我 运行 我的程序文件 MilaBild.py 第一次使用时:

pyinstaller -F -w MilaBild.py

创建“.spec”文件,我需要将以下内容添加到上面的其他评论中:

a.datas += [('rosa.png','C:\Python34\rosa.png', 'DATA')]

我的图像文件的名称是 rosa.png。它位于与我的程序文件 MilaBild.py.

相同的目录中

然后我还必须在我的实际程序文件中添加上面评论中提到的部分:

def resource_path(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)

然后我在将文件获取到变量的部分中添加并且它起作用了:

rosa = resource_path("rosa.png")

我尝试了很多,只是为了完成这项工作花了我一个小时。稍后我将尝试用两个图像、声音和子目录来制作它。但现在是 23:45 点钟,那将是另一天,到目前为止,我对此感到非常高兴,这对我来说是一个很好的突破。

终于比我在各种网页和此处找到的更简单了。

1) 当代码 运行 作为已编译的可执行文件时,您在代码中指定临时目录中的相对路径:

if getattr(sys, 'frozen', False): # Running as compiled
    running_dir = sys._MEIPASS + "/files/" # Same path name than pyinstaller option
else:
    running_dir = "./" # Path name when run with Python interpreter
iconFileName = running_dir + "mylogo.ico"
if os.path.isfile(iconFileName):
    root.iconbitmap(iconFileName) # Exemple for tkinter usage

2) 您在创建的临时目录中提供文件将存储在编译器选项中的路径:

pyinstaller --onefile --add-binary "mylogo.ico;files" -i mylogo.ico myMainPrg.py

这样,您就不必知道您的文件在开发中的完整路径以及您要在生产中安装它们的位置。

没什么好担心的。我有同样的问题,只是这样做就得到了答案...... 复制我所有的图像并将它们粘贴到 pyinstaller 创建的 dist/ 和 build/ 目录中,问题就解决了。 :)

为此苦苦挣扎。要知道的关键是,对于 --onefile 构建,您的图像存储在 sys._MEIPASS 文件夹中。

我的 tkinter 应用程序中的这行代码破坏了我的 .exe:

self.wm_iconbitmap("favicon.ico")

为了修复它,我将其替换为:

self.wm_iconbitmap(get_path("favicon.ico"))

其中 get_path() 是我添加到模块中的一个小函数:

def get_path(filename):
    if hasattr(sys, "_MEIPASS"):
        return os.path.join(sys._MEIPASS, filename)
    else:
        return filename

对于上下文,我 运行 在 CLI 中使用此命令构建 .exe:

pyinstaller --noconfirm --onefile --windowed --add-data "C:/Users/[...]/favicon.ico;."  "C:/Users/[...]/main.py"

注意,运行 这在 Win10 上。

感谢许多其他 Stack Overflow 贡献者。

当我尝试用一​​个小应用程序进行测试时,我在我的程序脚本中看到,我正在使用我的 C: 驱动器中的图像目录来引用图像,例如:

      xxx.setStyleSheet("background-image: url(C:\pictures\image1.jpg);"

而我应该确保图像与我的 F: 驱动器中的项目文件位于同一文件夹中

因此,当我将图像复制到 F: 驱动器中包含项目文件的同一文件夹时,我只使用了:

   xxx.setStyleSheet("background-image: url(image1.jpg;")

改成这个格式后效果很好

我只是将图像复制到项目文件夹,而没有在我的代码引用中使用该路径,但之前使用 C: 目录在我的代码中引用它。这就是它没有按预期工作的原因。

所以在我的脚本中使用正确的路径,我使用了这个命令:

     pyinstaller --windowed  --add-data "image1.jpg;." --add-data "image2.jpg;." --add-data "image3.jpg;." --icon=myLogo.ico myPythonFile.py

我在我的程序中使用的所有头像和背景图像都显示在它们应该在应用程序中的区域中,并且也可以在应用程序部署到的其他计算机上看到。

请管理员允许。我决定放下它,因为我或我的其他人明天可能需要它。我看到的其他答案在某种程度上让我感到困惑和困难

正在将图像转换为 base64 代码

首先在单独的代码中使用同名库将您的图像转换为 base64 代码,并将结果保存在另一个 python 文件中,以便您可以将其导入主 python 文件。这是必要的,否则在使用 pyinstaller 将 .py 转换为 .exe 并移动 exe 文件后,如果图像在新位置丢失,您将收到 file not found 错误。

import base64
pic = open('file.png', 'rb')
content = f'img = {base64.b64encode(pic.read())}\n'
pic.close()

with open('pic2str.py', 'w') as f:
    f.write(content) 

正在您的 python 主文件中导入 base64 代码

现在在你的主文件中导入变量,这样你的主代码中就不会使用你的图像文件地址了。

from pic2str import img

bg = base64.b64decode(img)
image = tk.PhotoImage(data=bg)
label = tk.Label(
    root,
    compound="center",
    text="Your Text",
    font=("Your Font", Your Font size),
    fg="Your Color",
    image=image)
label.pack(fill="both", expand=1)

现在您可以独立于使用的图像使用转换为 .exe 的文件。

清晰明确的指南

尽管网上有很多解释,但我花了几个小时才想出一个独立的应用程序,它包含多个图像,执行时不打开控制台,并且只组合在一个文件中。这是我的解决方案,至少适用于 Mac OS(我将 post 稍后用于 Windows 的解决方案):

第 1 步:更改目录

更改为包含可执行文件的目录:

cd PATH_OF_YOUR_FILE

确保您的程序所需的图像也在您要使其可执行的 Python 文件所在的文件夹中。

第 2 步:将代码添加到您的 Python 文件

将以下内容添加到要使其可执行的 Python 文件中:

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)

将文件名替换为 resource_path("FILENAME")

示例:

image1 = Image.open("image.png")

# to:

image1 = Image.open(resource_path("image.png"))

步骤 3:创建可执行文件

现在运行下面的代码(替换图像名称和文件名):

pyinstaller --onefile --windowed --add-data "picture1.jpeg:." --add-data "picture2.png:." your_file.py

注意:可以添加任意数量的图像。

说明:

--onefile:创建一个 one-file 捆绑的可执行文件。同义词:-F

--windowed:确保在执行过程中不打开任何控制台。同义词:-w--noconsole

大功告成!

该应用程序现在位于 dist 目录中,该目录与您的 Python 文件位于同一目录中。

现在应该可以将它拖到另一个 Mac 和 运行 那里,一旦通过 Settings -> Security & Privacy 启用。

希望对您有所帮助。享受结果,喝杯茶,坐下来。