fix: 多项稳定性修复与打包优化
- PyInstaller: runtime hook 预加载 osgeo DLL 避免 Qt5 符号冲突; spec 纳入 osgeo .py 文件 + 运行时 DLL 依赖 (ffi/lzma/bz2/expat/sqlite3); 移除 DLL 双副本防止 segfault - GDAL 环境: 新增 _MEIPASS/osgeo/data/gdal 路径搜索,改善打包后 GDAL_DATA 检测 - 预览生成器: 掩膜与底图同分辨率时跳过 Warp 加速读取 - 专题图: ConvexHull 坐标中心化修复 UTM 大坐标精度退化; 边界采样兜底防止外扩点为空; TIFF 已含 NaN 掩膜时跳过矢量擦除; 形态学闭运算填充掩膜小孔洞 - NDWI: int16→float32 防止减法溢出 - 面板注册表: 步骤模块分组重构 (模块一/二/三/四重划分)
This commit is contained in:
@ -60,6 +60,16 @@ def get_data_files():
|
||||
if os.path.exists(rthook_script):
|
||||
datas.append((rthook_script, "scripts"))
|
||||
|
||||
# 1-6. osgeo Python 模块(__init__.py, gdal.py, ogr.py 等)
|
||||
# ★ 关键:PyInstaller 会把 .py 文件打入 PYZ (嵌入 EXE),但 .pyd 文件
|
||||
# 作为 binaries 被放到 _internal/osgeo/ 物理目录下。当物理 osgeo/
|
||||
# 目录存在但没有 __init__.py 时,Python 无法将其识别为 package,
|
||||
# 导致 "import osgeo" 失败 → "GDAL 未安装"。
|
||||
# 解决方案:将 osgeo 的所有 .py 文件显式复制到物理 osgeo/ 目录。
|
||||
if os.path.isdir(CONDA_OSGEO_DLLS):
|
||||
for py_file in glob.glob(os.path.join(CONDA_OSGEO_DLLS, "*.py")):
|
||||
datas.append((py_file, "osgeo"))
|
||||
|
||||
return datas
|
||||
|
||||
datas = get_data_files()
|
||||
@ -90,13 +100,26 @@ def get_binaries():
|
||||
if os.path.exists(dll_path):
|
||||
binaries.append((dll_path, "."))
|
||||
|
||||
# 2-2. 搜集底层 GDAL/GEOS/PROJ 核心框架与二进制扩展
|
||||
if os.path.isdir(CONDA_OSGEO_DLLS):
|
||||
for dll_name in ["gdal.dll", "geos.dll", "geos_c.dll", "proj_9.dll"]:
|
||||
dll_path = os.path.join(CONDA_OSGEO_DLLS, dll_name)
|
||||
# 2-1b. Python C 扩展的运行时依赖 DLL(_ctypes → ffi.dll, _lzma → liblzma.dll 等)
|
||||
# 这些 DLL 位于 Conda 环境的 Library/bin,PyInstaller 分析时无法自动发现
|
||||
CONDA_LIBRARY_BIN = os.path.join(CONDA_ENV_DLLS, "Library", "bin")
|
||||
if os.path.isdir(CONDA_LIBRARY_BIN):
|
||||
for dll_name in [
|
||||
"ffi.dll", # _ctypes.pyd 依赖
|
||||
"liblzma.dll", # _lzma.pyd 依赖
|
||||
"libbz2.dll", # _bz2.pyd 依赖
|
||||
"libexpat.dll", # pyexpat.pyd 依赖
|
||||
"sqlite3.dll", # _sqlite3.pyd 依赖
|
||||
]:
|
||||
dll_path = os.path.join(CONDA_LIBRARY_BIN, dll_name)
|
||||
if os.path.exists(dll_path):
|
||||
binaries.append((dll_path, "."))
|
||||
|
||||
# 2-2. 搜集底层 GDAL/GEOS/PROJ 核心框架与二进制扩展
|
||||
# ★ 注意:gdal.dll / geos.dll / geos_c.dll / proj_9.dll 不再显式添加,
|
||||
# PyInstaller 会自动将它们收集到 osgeo/ 目录(随 .pyd 依赖解析)。
|
||||
# 显式添加到根目录会导致 DLL 双副本冲突 → segfault。
|
||||
if os.path.isdir(CONDA_OSGEO_DLLS):
|
||||
# 映射 Python 3.12 对应的底层二进制接口 (C-Extension)
|
||||
for pyd_name in [
|
||||
"_gdal.cp312-win_amd64.pyd",
|
||||
@ -185,6 +208,10 @@ a.binaries = [
|
||||
if not x[0].lower().startswith(('msvcp140', 'vcruntime140'))
|
||||
]
|
||||
|
||||
# ★ 注意:.libs 目录中的 PROJ/GEOS/GDAL DLL 副本无需删除。
|
||||
# rthook_add_dll_dirs.py 运行时钩子会在 PyQt5 之前预加载 osgeo/ 的所有 DLL,
|
||||
# 避免了 DLL 加载顺序导致的 segfault。各包的 .libs 副本可以安全共存。
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
# 生成物理启动核心
|
||||
@ -198,7 +225,7 @@ exe = EXE(
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=False, # 禁用 UPX 暴力压缩,保护二进制 C++ 区段完整性
|
||||
console=False, # ⚠️ 维持开启控制台,拒绝绝对静默崩溃
|
||||
console=False, # GUI 应用,不显示控制台
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
|
||||
Reference in New Issue
Block a user