PySide2+cx_freeze打包程序在其他PC上JPEG无法显示,PNG正常
问题背景
基于PySide2 v5.15.5(Windows10 + miniforge Python3.10.6)开发的应用,在开发机上直接运行脚本或cx_freeze打包后的程序均正常,但将打包文件夹复制到无Python/Qt环境的机器上时,JPEG图片无法加载,控制台输出QPainter::begin: Paint device returned engine == 0等错误,QPixmap尺寸为0x0,QImageReader.supportedImageFormats()返回列表不含jpg格式,虽打包目录中存在qjpeg.dll和libjpeg.dll但无效。转为PNG格式后程序正常运行。
根本原因
cx_freeze打包时虽复制了Qt的imageformats插件,但存在三个关键问题:
- Qt无法自动识别插件路径,导致
qjpeg.dll未被加载 - 插件依赖的
libjpeg.dll可能未被复制到插件可访问的路径 - 代码中图片加载方式存在错误,放大了打包后的路径/插件问题
具体修复步骤
1. 修正setup.py,正确复制插件目录
修改build_exe_options中的include_files,手动指定将PySide2的imageformats插件复制到打包后的plugins/imageformats目录:
import sys import os from cx_Freeze import setup, Executable from PySide2 import QtCore # 获取PySide2的imageformats插件路径 imageformats_path = os.path.join(os.path.dirname(QtCore.__file__), "Qt", "plugins", "imageformats") build_exe_options = { "packages": ["atexit"], "include_files": [ "image.jpg", "uiFile.ui", "qt.conf", # 后续创建的配置文件 (imageformats_path, "plugins/imageformats"), # 复制插件到指定路径 ], "excludes": ["tkinter"], "build_exe": "MyScript", } base = None # 打包GUI程序建议启用Win32GUI,避免控制台窗口 if sys.platform == "win32": base = "Win32GUI" setup( name="MyScript", version="0.1", description="My Script", options={"build_exe": build_exe_options}, executables = [Executable("MyScript.pyw", base=base)])
2. 创建qt.conf指定插件路径
在项目根目录创建qt.conf文件,内容如下:
[Paths] Plugins = plugins
该文件告诉Qt去打包目录下的plugins文件夹寻找插件。
3. 手动检查并补充依赖DLL
打开打包后的MyScript/plugins/imageformats目录,确认存在qjpeg.dll和libjpeg.dll,如果缺失,从开发环境的PySide2/Qt/plugins/imageformats目录复制这两个文件到该位置。
4. 修正代码中的图片加载逻辑
原代码中QPixmap.fromImage(image_filename)用法错误,fromImage的参数是QImage对象而非文件名,修改为:
# 直接用QPixmap加载文件 pixmap = QtGui.QPixmap(image_filename) # 或者先加载QImage再转Pixmap(可选,适合需要预处理图片的场景) # image = QtGui.QImage(image_filename) # pixmap = QtGui.QPixmap.fromImage(image) # 加载后先检查是否有效 if pixmap.isNull(): print(f"Failed to load image: {image_filename}") return qp = QtGui.QPainter(pixmap) # 后续绘制逻辑...
验证
打包完成后,在目标机器上运行程序,调用print(QtGui.QImageReader.supportedImageFormats()),输出列表中应包含b'jpg'和b'jpeg',JPEG图片可正常加载显示。
内容的提问来源于stack exchange,提问作者DrAl

