Windows 桌面工具,用于批量打印 PDF 和图片。可调用打印机原生设置并应用到全部文档,也支持对单个文档单独设置。
免安装绿色版见 Releases:下载 zip 解压后,
双击 批量打印.exe 即可运行,无需安装 Python。
详见开发蓝图:批量打印应用_开发蓝图.md
- 三种方式:拖拽文件/文件夹到窗口、添加文件(可多选)、添加文件夹(递归扫描所有子目录)
- 支持格式:
- PDF:
.pdf - 图片:
.jpg.jpeg.png.bmp.tif.tiff.gif
- PDF:
- 自动去重:同一个文件不会被重复添加
- 自动识别 PDF 页数
- 全程不卡界面:扫描目录、读页数都在后台线程完成,再分批插入列表; 过程中状态栏依次显示「正在扫描… X/Y」→「正在加载… X/Y」,导入几百个文件也能随时点
列表共 8 列:勾选 / 预览 / 文件名 / 类型 / 页数 / 份数 / 状态 / 属性
- 勾选:只有勾选的文件会被打印
- 预览:首页缩略图。只渲染屏幕上可见的行,滚到哪生成到哪(文件再多也不卡)
- 类型:
PDF 文档、JPG 图片、PNG 图片…(图片按实际扩展名显示) - 份数:可直接在行内修改。加粗 = 已为该文档单独设置(不再跟随全局);常规字重 = 跟随全局
- 状态:待打印 / 打印中 / 完成 / 失败(失败时鼠标悬停可看原因)
- 属性:打开该文档的独立设置窗口(见第 5 节)
- 工具栏右侧常驻统计:
已勾选 12 / 95 个文件(约 240 页),页数已算入份数 - 列表操作:移除选中 / 清空 / 全选 / 全不选
界面上用灰色边框单独框出,与单文档设置区分:
- 打印机:枚举本机所有打印机(含网络打印机),默认选中系统默认打印机
- 打印机设置…:调出打印机自带的原生属性对话框——双面、彩色/黑白、纸张大小、纸盒来源等 由打印机驱动自己提供,设置结果应用到所有文档
- 份数:应用到所有未单独设置份数的文档
- 图片排版:
等比缩放居中(默认):完整显示,不裁切等比铺满(裁切):铺满纸张,超出部分裁掉拉伸铺满:拉伸填满,不保持比例
- 自动匹配文档方向(默认开启):横向的页面/图片自动用横向打印,纵向的用纵向。 PDF 逐页判断,同一份文档里混合方向也能各自匹配。关掉则一律用你手动设的方向
- 切换打印机时会自动重置打印机设置(旧设置属于旧打印机,不通用),状态栏有提示
任何一项不设置就继承全局:
- 份数:列表行内直接改,或在属性窗口里设
- 页面范围(仅 PDF):如
1-3,5;留空 = 全部页 - 单独的打印机设置:为该文档单独调出打印机原生对话框,与全局互不影响
- 可随时「恢复继承全局」
- 大图预览(420px),不是小缩略图
- 翻页导航:
◀ 上一页/第 [n] / N 页(可直接输入页码跳转)/下一页 ▶,能看到 PDF 的每一页 - 按需渲染当前页并缓存,打开上百页的 PDF 也不卡
- 设了「页面范围」时,预览下方实时提示当前页 「本页在打印范围内」(绿)或 「本页不在打印范围内,不会打印」(橙)
- 图片只有一页,自动隐藏翻页控件
- 严格按列表顺序串行打印(顺序可控,不会乱序)
- 每个文件是独立的打印任务,不合并
- 底部进度条 + 状态栏显示当前正在打印的文件
- 可随时停止(完成当前文件后停止)
- 失败的文件标记为「失败」并记录原因,不影响后续文件继续打印
- 打印引擎:Windows GDI + DEVMODE 管线。PDF 用 PyMuPDF 逐页渲染、图片用 Pillow,
统一绘制到带 DEVMODE 的打印机 DC 上;自动方向通过逐页
ResetDC实现
- 不保存打印预设,也不记录历史
- 打印机设置(DEVMODE)仅在本次会话内有效,重启程序后回到打印机默认
- 统计里的页数是约值:双面打印时实际张数会减半,驱动层设置本程序无法感知
- Windows 10/11,Python 3.11+
- 依赖见
requirements.txt:PySide6 / PyMuPDF / Pillow / pywin32
pip install -r requirements.txt注意:PySide6 目录层级很深,若安装时报
OSError: [Errno 2] ...或长路径错误, 需要启用 Windows 长路径支持(管理员 PowerShell):New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" ` -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force然后重新执行安装。
python run.pybatchprint/
├── app.py 程序入口
├── logging_setup.py 日志
├── core/
│ ├── importer.py 文件导入/扫描
│ ├── scanner.py 后台扫描线程(展开目录/读页数,带进度)
│ ├── settings.py 数据模型(全局/单文档设置、任务)
│ ├── printers.py 打印机枚举、原生设置对话框(DEVMODE)
│ ├── engine.py 打印引擎(GDI + DEVMODE,核心)
│ ├── runner.py 后台调度线程
│ └── thumbnailer.py 异步缩略图
└── ui/
├── main_window.py 主窗口
└── properties_dialog.py 单文档属性对话框
用 PyInstaller 打成目录版(onedir)——整个 dist/批量打印/ 文件夹拷到任意位置,
双击里面的 批量打印.exe 即可运行,目标机器无需安装 Python。
python -m PyInstaller --noconfirm --clean 批量打印.spec产物:dist/批量打印/(约 187 MB)
批量打印.exe:启动器(约 10 MB)_internal/:所有依赖(Qt、PyMuPDF、pywin32 等)——不要单独移动 exe,要连同 _internal 整个文件夹一起拷贝
说明:exe 未做代码签名,别人首次运行可能弹 SmartScreen 提示,点「更多信息 → 仍要运行」即可。 出错日志在
%APPDATA%\BatchPrint\logs\batchprint.log。
改动 UI / 缩略图相关代码时请留意,以下几条是排查卡顿时定位到的,改回去会重新引发界面"未响应":
- QPixmap 只能在 GUI 线程用。工作线程里一律只产出
QImage,QPixmap 在主线程转换 (见core/thumbnailer.py)。曾经在工作线程调QPixmap.fromImage(),导致导入 95 个文件 时主线程被锁死约 4 秒。 - 不要一次性渲染所有缩略图。缩略图是 Python 线程里跑 PyMuPDF,会长时间持有 GIL 把主线程
饿死。现在只渲染可见行(
_request_visible_thumbs)——95 个文件只渲染约 10 个, 主线程最长阻塞从 3952ms 降到约 25ms。同理,属性窗口的预览也是按需渲染当前页。 - 表格列宽别用
ResizeToContents(文件名列的 Stretch 除外)。每次缩略图到位都会重新 测量所有行,行一多就是 O(行数²)。
- M0 骨架 / M1 导入+列表 / M2 打印机+设置 / M3 打印引擎(已用「打印到 PDF」端到端验证)
- M4 批量串行调度、进度、停止 / M5 单文档设置
- M6 打磨与 PyInstaller 打包(onedir 绿色版)
