【问题标题】:Pygame not loading png after making .exe with Pyinstaller使用 Pyinstaller 制作 .exe 后 Pygame 未加载 png
【发布时间】:2017-05-03 09:51:39
【问题描述】:

我一直在尝试从我的 .py 游戏制作一个 .exe,这真的很令人沮丧。

我正在使用 Python 3.5.2、Pygame 1.9.2 和 Pyinstaller 3.2。

游戏以 .py 格式完美运行,但是在我输入 pyinstaller --debug game.py 后,构建了 .exe 并运行它,我得到以下信息:

debug screen

这些是 game.py 中可能与错误相关的代码行:

from os import path
img_dir = path.join(path.dirname(__file__), 'sprites')
title_screen = pygame.image.load(path.join(img_dir, 'title_screen.png'))

我认为这一定与 pyinstaler 无法获取我的 sprites 文件夹有关,因为当我尝试运行 pyinstaller --icon=/sprites/icon.ico game.py 时,我得到了这个:

icon error screen

但如果我使用pyinstaller --icon=icon.ico game.py,它会很好地加载图标。

这是我的规范文件:

# -*- mode: python -*-

block_cipher = None

added_files = [
         ( '/sprites', 'sprites' ),
         ( '/music', 'music' ),
         ( 'Heavitas.ttf', '.'),
         ( 'Roboto-Light.ttf', '.'),
         ( 'high scores.csv', '.')
         ]


a = Analysis(['spec_file.py'],
             pathex=['C:\\Users\\rodri\\Documents\\Code\\The Color That Fell From The Sky'],
             binaries=None,
             datas=added_files,
             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,
          exclude_binaries=True,
          name='spec_file',
          debug=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='spec_file')

【问题讨论】:

  • 您可以将所有资源转换为 base64 字符串(可能先压缩),将它们包含在脚本中并在执行时写入/重新创建文件

标签: python-3.x pygame pyinstaller


【解决方案1】:

当您使用 PyInstaller 编译时,所有文件都会在您运行 exe 时移动到不同的目录。因此,要到达此位置,请在生成路径之前将其添加到代码的开头

import sys

if getattr(sys, 'frozen', False): # PyInstaller adds this attribute
    # Running in a bundle
    CurrentPath = sys._MEIPASS
else:
    # Running in normal Python environment
    CurrentPath = os.path.dirname(__file__)

然后可以从您的位置生成所有文件夹路径

spriteFolderPath = path.join(CurrentPath, 'sprites') # Do the same for all your other files

然后,当你得到你正在执行的位置时,你可以从那里获取所有文件:

title_screen = pygame.image.load(path.join(spriteFolderPath, 'title_screen.png')) # Use spriteFolderPath instead of img_dir

我还看到你有其他字体/东西,你可以这样做来加载它们

fontRobotoLight = pygame.font.Font(path.join(CurrentPath, 'Roboto-Light.ttf'))

对于您的图标,只需在您的主文件夹中粘贴一个临时的icon.ico 并输入 pyinstaller -i "icon.ico" "spec_file.spec"

最后,由于我之前遇到过同样的问题,我建议您只需运行 pyinstaller "spec_file.spec" 即可编译您的 exe

【讨论】:

  • 图标建议有效,但我仍然收到同样的错误,说它无法加载 title_screen.png。此外,pyinstaller "spec_file.spec" 返回 ValueError: script 'spec_file.py' not found。不过还是谢谢。
  • @RodrigoNascimento 我写了“spec_file”,我的意思是在“”之间输入您的规范文件的名称。对不起,这很模棱两可。否则,它应该可以工作。
  • 我知道。我的规格文件实际上名为“spec_file.spec”。
【解决方案2】:

终于成功了!

以下是我所做的快速指南,以防您因为遇到类似问题而阅读此内容。 (我使用 Python 3.5.2、Pygame 1.9.2 和 Pyinstaller 3.2)

准备您的代码

就像 C._ 在另一个答案中解释的那样(谢谢),以防您像这样加载文件:

import os
folder_path = os.path.join(path.dirname(__file__), 'folder')
some_image = pygame.image.load(os.path.join(folder_path, 'some_image.png'))

改为这样做:

import sys
import os
# If the code is frozen, use this path:
if getattr(sys, 'frozen', False):
    CurrentPath = sys._MEIPASS
# If it's not use the path we're on now
else:
    CurrentPath = os.path.dirname(__file__)
# Look for the 'sprites' folder on the path I just gave you:
spriteFolderPath = os.path.join(CurrentPath, 'sprites')
# From the folder you just opened, load the image file 'some_image.png'
some_image = pygame.image.load(path.join(spriteFolderPath, 'some_image.png'))

这是必需的,因为当您冻结代码时,文件将被移动到与您之前使用的文件夹不同的文件夹中。确保对所有文件执行此操作。

这是另一个例子:

if hasattr(sys, '_MEIPASS'):  # the same logic used to set the image directory
    font = path.join(sys._MEIPASS, 'some_font.otf')  # specially useful to make a singlefile .exe
font = pygame.font.Font(font, size)
# Don't ask me the difference between hasattr and getattr because I don't know. But it works.

图标(可选)

如果你想要一个不是 pyinstaller 默认的图标,你可以选择一个 png 图像并使用一些在线转换器(谷歌它)将它转换为 .ico。之后,将 .ico 文件放在 .py 文件所在的同一文件夹中。

制作规范文件

此时,您应该知道您是想要一个独立的 .exe 文件还是要压缩并发送给人们的一堆单独的文件。在任何情况下,请在 .py 文件所在的文件夹上打开终端。

如果你想要一个文件,使用这个:

pyinstaller --onefile --icon=icon_file.ico game_file.py

如果你不这样做,使用这个:

pyinstaller --icon=icon_file.ico game_file.py

如果您现在不想设置图标,请不要使用--icon 部分。您可以稍后更改。您以后无法更改的是 --onefile 选项(至少据我所知)。

将创建一个名为 game_file.spec 的文件。它将自动从 game_file.py 中获取名称。如果他们有不同的名字,你可能会搞砸,所以现在不要有创意。如果您选择单个文件,它应该如下所示:

# -*- mode: python -*-

block_cipher = None

a = Analysis(['game_file.py'],
             pathex=['C:\\some\\path\\The path where your .py and .spec are'],
             binaries=None,
             datas=None,
             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,
          exclude_binaries=True,
          name='game_file',
          debug=False,
          strip=False,
          upx=True,
          console=True , icon='icon_file.ico')

如果你选择了一堆文件,你会看到这个附加部分:

coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='game_file')

block_cipher = None 之后,您将添加游戏加载的文件。像这样:

added_files = [
         ( 'a folder', 'b folder' ),  # Loads the 'a folder' folder (left) and creates
                                      # an equivalent folder called 'b folder' (right)
                                      # on the destination path
         ( 'level_1/level2', 'level_2' ),  # Loads the 'level_2' folder
                                           # that's inside the 'level_1' folder
                                           # and outputs it on the root folder
         ( 'comic_sans.ttf', '.'),  # Loads the 'comic_sans.ttf' file from
                                    # your root folder and outputs it with
                                    # the same name on the same place.
         ( 'folder/*.mp3', '.')  # Loads all the .mp3 files from 'folder'.
         ]

现在您必须在此处添加“added_files”:

a = Analysis(['game_file.py'],
                 pathex=['C:\\some\\path\\The path where your .py and .spec are'],
                 binaries=None,
                 datas=added_files,  # Change 'None' to 'added_files' here
                                     # Leave everything else the way it is.
                 hiddenimports=[],
                 hookspath=[],
                 runtime_hooks=[],
                 excludes=[],
                 win_no_prefer_redirects=False,
                 win_private_assemblies=False,
                 cipher=block_cipher)

您还可以更改一些设置:

exe = EXE(pyz,
              a.scripts,
              exclude_binaries=True,
              name='game_file',  # Name of the output file. Equivalent to '--name'
                                 # Don't change it.
              debug=False,  # If True shows a debug screen on start. Equivalent to '--debug'.
              strip=False,
              upx=True,  # Compresses executable files and libraries
              # If console=True, a console screen will be shown on start up.
              # icon= is the location of the icon of the exe.
              console=True , icon='icon_file.ico')

如果你没有像我告诉你的那样在 cmets 上没有更改 exe 的路径或输出名称,我们只需要运行它,之前创建的 .exe 文件就会被更新。在命令窗口输入:

pyinstaller game_file.spec

请记住,game_file.spec 是我们刚刚编辑的文件,而“game_file”是我用作示例的随机名称。另请注意,没有--some_option,因为它们不适用于规范文件。这就是为什么您必须直接在脚本中更改它们的原因。 --onefile 在这里也不起作用,也不能在脚本中完成,这就是我之前告诉你这样做的原因。

您将看到在 .spec 文件所在的同一文件夹中创建了两个文件夹。一个名为“Dist”的文件包含 exe 文件,如果您没有使用--onefile,它还应该有一堆其他文件,您需要将这些文件与 exe 一起压缩以与其他人共享应用程序。还有一个“Buid”文件夹,但我不知道它的用途,因为您不需要它来使用应用程序。

原来如此。它应该适合你。

我提出问题时的错误是我不知道sys._MEIPASS 部分(再次感谢C._),我的spec 文件的名称与我的py 文件不同,我使用'/sprites' 而不是'sprites' in added_files 并且不知道我应该运行 spec 文件而不是 py 文件。

有关 Pyinstaller 的更多信息,请查看 manual,但由于它远非良好且有时会产生误导,因此您最好使用 Google。

【讨论】:

    猜你喜欢
    • 2022-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多