SlideCombine/build_exe.py

387 lines
10 KiB
Python
Raw Normal View History

2025-11-24 17:24:27 +08:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PDF书签合并工具 - 自动打包脚本
使用PyInstaller将Python程序打包成独立的exe文件
"""
import os
import sys
import subprocess
import shutil
from pathlib import Path
def check_pyinstaller():
"""检查是否安装了PyInstaller"""
try:
subprocess.run([sys.executable, "-c", "import PyInstaller"],
check=True, capture_output=True)
print("✅ PyInstaller 已安装")
return True
except subprocess.CalledProcessError:
print("❌ PyInstaller 未安装")
return False
def install_pyinstaller():
"""安装PyInstaller"""
print("正在安装 PyInstaller...")
try:
subprocess.run([sys.executable, "-m", "pip", "install", "pyinstaller"],
check=True)
print("✅ PyInstaller 安装成功")
return True
except subprocess.CalledProcessError as ex:
print(f"❌ PyInstaller 安装失败: {ex}")
return False
def clean_build():
"""清理之前的构建"""
print("🧹 清理之前的构建...")
folders_to_remove = ['build', 'dist', '__pycache__']
files_to_remove = ['SlideCombine.spec']
for folder in folders_to_remove:
if os.path.exists(folder):
shutil.rmtree(folder)
print(f" 已删除文件夹: {folder}")
for file in files_to_remove:
if os.path.exists(file):
os.remove(file)
print(f" 已删除文件: {file}")
def create_spec_file():
"""创建PyInstaller配置文件"""
spec_content = '''
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['slide_combine.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='SlideCombine',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='app.ico', # 图标文件(如果存在)
version='version_info.txt' # 版本信息(如果存在)
)
'''
with open('SlideCombine.spec', 'w', encoding='utf-8') as f:
f.write(spec_content)
print("✅ 已创建 SlideCombine.spec 配置文件")
def create_version_info():
"""创建版本信息文件"""
version_info = '''
# UTF-8
#
# For more details about fixed file info 'ffi' see:
# http://msdn.microsoft.com/en-us/library/ms646997.aspx
VSVersionInfo(
ffi=FixedFileInfo(
# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
# Set not needed items to zero 0.
filevers=(2,0,0,0),
prodvers=(2,0,0,0),
# Contains a bitmask that specifies the valid bits 'flags'r
mask=0x3f,
# Contains a bitmask that specifies the Boolean attributes of the file.
flags=0x0,
# The operating system for which this file was designed.
# 0x4 - NT and there is no need to change it.
OS=0x4,
# The general type of file.
# 0x1 - the file is an application.
fileType=0x1,
# The function of the file.
# 0x0 - the function is not defined for this fileType
subtype=0x0,
# Creation date and time stamp.
date=(0, 0)
),
kids=[
StringFileInfo(
[
StringTable(
u'080404B0',
[StringStruct(u'CompanyName', u'PDF书签合并工具'),
StringStruct(u'FileDescription', u'PDF书签合并工具 - 用于从PDF文件夹中提取书签信息与TXT元数据文件合并'),
StringStruct(u'FileVersion', u'2.0.0.0'),
StringStruct(u'InternalName', u'SlideCombine'),
StringStruct(u'LegalCopyright', u'Copyright (C) 2024'),
StringStruct(u'OriginalFilename', u'SlideCombine.exe'),
StringStruct(u'ProductName', u'PDF书签合并工具'),
StringStruct(u'ProductVersion', u'2.0.0.0')])
]),
VarFileInfo([VarStruct(u'Translation', [2052, 1200])])
]
)
'''
with open('version_info.txt', 'w', encoding='utf-8') as f:
f.write(version_info)
print("✅ 已创建 version_info.txt 版本信息文件")
def build_exe():
"""构建exe文件"""
print("🔨 开始构建 exe 文件...")
try:
# 构建命令
cmd = [
sys.executable, '-m', 'PyInstaller',
'--clean',
'--onefile',
'--windowed',
'--name=SlideCombine',
'slide_combine.py'
]
# 如果有图标文件,添加图标参数
if os.path.exists('app.ico'):
cmd.insert(-1, '--icon=app.ico')
print("✅ 已找到图标文件: app.ico")
else:
print("⚠️ 未找到图标文件,将使用默认图标")
print(f"执行命令: {' '.join(cmd)}")
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
print("✅ 构建成功!")
return True
except subprocess.CalledProcessError as ex:
print(f"❌ 构建失败: {ex}")
if ex.stderr:
print(f"错误信息: {ex.stderr}")
return False
def create_release_package():
"""创建发布包"""
print("📦 创建发布包...")
# 检查dist文件夹
dist_path = Path('dist')
if not dist_path.exists():
print("❌ 未找到 dist 文件夹")
return False
# 查找生成的exe文件
exe_files = list(dist_path.glob('*.exe'))
if not exe_files:
print("❌ 未找到生成的 exe 文件")
return False
exe_file = exe_files[0]
print(f"✅ 找到 exe 文件: {exe_file}")
# 创建发布包文件夹
import datetime
version = "2.0.0"
date = datetime.datetime.now().strftime("%Y%m%d")
package_name = f"SlideCombine_v{version}_{date}"
package_path = Path(package_name)
if package_path.exists():
shutil.rmtree(package_path)
package_path.mkdir()
print(f"✅ 创建发布包文件夹: {package_name}")
# 复制exe文件
shutil.copy2(exe_file, package_path / 'SlideCombine.exe')
print("✅ 复制主程序文件")
# 创建使用说明
readme_content = f"""PDF书签合并工具 v{version} 使用说明
=====================================
系统要求
- Windows 7 SP1 或更高版本
- 无需额外安装软件绿色软件
使用方法
1. 双击运行 SlideCombine.exe
2. 选择三个路径
- PDF文件夹路径包含 FreePic2Pdf_bkmk.txt 文件的文件夹
- TXT源文件路径包含元数据 TXT 文件的路径
- 输出路径合并后文件的保存位置
3. 点击"开始合并"按钮
4. 等待处理完成
示例目录结构
PDF文件夹/
CH-875 1-3/FreePic2Pdf_bkmk.txt
CH-875 4-6/FreePic2Pdf_bkmk.txt
TXT源文件/
CH-875 1-3.txt
CH-875 4-6.txt
输出结果
输出路径/CH-875.txt (合并后的文件)
特点
- 🚀 运行速度快
- 📦 绿色软件无需安装
- 🎯 智能文件分组
- 📊 详细处理日志
- 🌍 支持多种文件编码
- 💾 独立程序无依赖
故障排除
- 如果程序无法启动请检查是否有杀毒软件阻止运行
- 确保输入的路径存在且有访问权限
- 查看日志输出了解详细的处理信息
版本信息
- 程序版本v{version}
- 构建日期{date}
- 开发语言Python
- 界面框架Tkinter
技术支持
这是一个绿色软件解压即用无需安装任何依赖项
"""
with open(package_path / '使用说明.txt', 'w', encoding='utf-8') as f:
f.write(readme_content)
print("✅ 创建使用说明")
# 创建启动脚本
bat_content = '''@echo off
title PDF书签合并工具 v2.0
echo 启动 PDF书签合并工具...
echo.
if exist "SlideCombine.exe" (
start "" "SlideCombine.exe"
echo 程序已启动
) else (
echo 错误未找到 SlideCombine.exe
echo 请确保在正确的目录中运行此脚本
pause
)
timeout /t 2 >nul
'''
with open(package_path / '启动程序.bat', 'w', encoding='gbk') as f:
f.write(bat_content)
print("✅ 创建启动脚本")
# 获取文件大小
exe_size = (package_path / 'SlideCombine.exe').stat().st_size
size_mb = exe_size / (1024 * 1024)
size_kb = exe_size / 1024
print(f"""
发布包创建完成
📁 发布包位置: {package_path.absolute()}
💾 主程序大小: {size_kb:.1f} KB ({size_mb:.1f} MB)
📋 包含内容:
SlideCombine.exe (主程序)
使用说明.txt (用户指南)
启动程序.bat (快捷启动)
🎉 部署说明:
1. 将整个 {package_name} 文件夹复制到目标电脑
2. 双击"启动程序.bat"或直接运行"SlideCombine.exe"
3. 无需安装任何软件绿色环保
""")
return True
def main():
"""主函数"""
print("="*50)
print(" PDF书签合并工具 - 自动打包脚本")
print("="*50)
print()
# 检查Python版本
if sys.version_info < (3, 7):
print("❌ 需要 Python 3.7 或更高版本")
sys.exit(1)
print(f"✅ Python版本: {sys.version}")
# 检查主程序文件
if not os.path.exists('slide_combine.py'):
print("❌ 未找到 slide_combine.py 文件")
print("请确保在项目根目录下运行此脚本")
sys.exit(1)
# 检查/安装PyInstaller
if not check_pyinstaller():
print("尝试自动安装 PyInstaller...")
if not install_pyinstaller():
print("请手动安装 PyInstaller: pip install pyinstaller")
sys.exit(1)
# 清理之前的构建
clean_build()
# 创建配置文件
create_spec_file()
create_version_info()
# 构建exe文件
if not build_exe():
print("❌ 构建失败,请检查错误信息")
sys.exit(1)
# 创建发布包
if not create_release_package():
print("❌ 创建发布包失败")
sys.exit(1)
print("🎉 打包完成!")
if __name__ == "__main__":
main()