InkSwarm 是一个面向 Windows 的多打印机调度与色彩管理工具,目标不是替代打印机驱动,而是把 任务分发、ICC 色彩转换、驱动预设恢复、缓存复用、日志追踪 这些环节组织成一个稳定、可控、适合生产环境的打印流水线。
它特别适合这样一类场景:同一批 PDF 或图片需要发往多台桌面打印机并行输出,但又不能牺牲驱动层的纸张、墨水、介质、打印质量等原厂控制能力。InkSwarm 让你继续使用原厂驱动,同时把多机负载均衡、色彩管理和运行监控统一收口到一个 GUI 程序里。
- 多 Worker 并行调度:按“速度”比例自动分配任务份数,同时保持发送顺序轮询;可选尾段动态均衡会在收尾阶段接手未发送的剩余份数,减少单机拖尾。
- 保留原厂驱动能力:纸张、介质、打印质量、双向校准等仍交给打印机驱动处理。
- ICC 色彩管理:支持输入/输出 ICC、渲染意图、黑点补偿,适合不同机型、纸张、墨水组合。
- 同任务只 RIP 一次:同一个 Worker 处理同一个任务时只渲染一次并复用缓存,避免重复开销。
- 面向生产环境的防护:支持自动清缓存、队列上限限流、RIP 精度限制、忽略页边距、按月统计输出结果。
- 可追踪性强:普通日志、debug 日志、统计 CSV 分层记录,便于长期运行和问题排查。
现成的批量打印方案在“多机并发 + 色彩管理 + 原厂驱动兼容性”这个组合场景下并不理想。
一类方案擅长批量投递,但对不同打印机、不同纸张墨水组合的色彩管理支持不足。另一类方案虽然能做 ICC 转换,但常常把整条链路绑死在自己的渲染和发送方式上,稳定性、性能、可维护性都不够理想,尤其是在多台打印机并发工作时容易暴露问题。
InkSwarm 的思路是把问题拆开:
- 调度 由程序自身负责。
- 色彩管理 由可控的渲染链完成。
- 纸张和驱动细节 交还给原厂驱动。
- 重复任务 通过缓存复用避免重复 RIP。
这样做的结果是,既能保留生产环境里最关键的驱动兼容性,又能获得独立、透明、可扩展的任务调度能力。
- GUI:PySide6
- PDF 渲染:pypdfium2 / PDFium
- 位图与 ICC 处理:Pillow + ImageCms(LittleCMS)
- Windows 打印接口:pywin32(Printer DC / Spooler)
- 驱动预设保存与恢复:PrintUI /
.dat快照 - 缓存与配置:本地目录结构 + JSON
- 日志与统计:文本日志、debug 日志、按月 CSV
flowchart LR
A[GUI / PySide6] --> B[ConfigStore]
A --> C[Task List]
A --> D[Workers List]
A --> E[Run Options]
C --> F[PrintController]
D --> F
E --> F
F --> G[WeightedScheduler]
F --> H[WorkerRuntime x N]
H --> I[Renderer]
I --> J[PDFium]
I --> K[Pillow + LittleCMS]
I --> L[Render Cache]
H --> M[PrinterSpooler]
H --> N[PrintUI Restore]
M --> O[Windows Spooler]
O --> P[Original Printer Driver]
P --> Q[Printer]
F --> R[App Log]
F --> S[Debug Log]
F --> T[Statistics CSV]
- 安装 Python 和依赖。
- 启动程序,准备好程序根目录下的
Workers或Workers_*方案组目录。 - 为每个 Worker 配置打印机名称、速度、当前预设。
- 在对应 preset 中放入 ICC、驱动快照或其他预设文件。
- 通过 GUI 打开驱动首选项,确认纸张和介质参数,然后导出当前驱动设定。
- 将 PDF 或图片拖入任务列表,设置份数。
- 在设置面板中按需要启用自动清缓存、自适应纸张方向、忽略页边距、缩放模式、RIP 精度限制、Worker 最大排队数、尾段动态均衡等选项。
- 点击“开始发送”,由调度器按 Worker 速度和当前状态并行分发任务。
任务列表是 InkSwarm 的入口区域。每个条目对应一个独立打印任务,核心字段包括:
- 是否启用
- 文件名
- 份数
- 打印尺寸
- 当前状态
- 分配摘要
任务支持拖放添加,份数可以逐项修改,也可以批量修改。每个任务前的复选框用于控制该文件是否参与下一次发送。程序会根据当前勾选的任务、启用的 Worker 和速度参数,为每个任务先计算应分配到各台机器的份数,再交给调度器按轮询顺序发出。尾段动态均衡启用时,初始分配仍按这套静态结果执行;只有静态任务全部入队后,空闲 Worker 才会在达到设定空闲时间后接手其他 Worker 尚未发送的剩余份数。
列表右侧会显示当前选中任务的缩略图,用于快速核对内容方向和大致版式。
InkSwarm 支持常见的生产输入类型:
- JPG / JPEG
- PNG
- TIFF / TIF
- BMP
程序会先读取输入文件的物理尺寸信息,用于后续 1:1 输出。对于位图输入,会根据图像内 DPI 换算毫米尺寸;缺失 DPI 时则使用默认值估算。对于 PDF,则直接读取页面尺寸。位图输入若带有 EXIF 方向标记(常见于手机、相机照片),会先按标记旋转/镜像到正立方向,尺寸计算、缩略图和打印输出都与看图软件所见一致。
为了降低资源占用并避免大图导致的渲染/发送不稳定,程序提供 RIP 精度限制。启用后:
- PDF 渲染 DPI 会被限制在指定上限以内。
- 位图如果超过目标物理尺寸对应的最大像素数,也会在进入缓存前缩小到上限。
程序还支持 自适应纸张方向:
- 可强制统一为 Portrait 或 Landscape。
- 不管输入文件本身方向如何,都会在缓存生成阶段统一旋转到目标朝向。
色彩管理是 InkSwarm 的核心功能之一。色彩链路由两部分组成:
- 全局 CMYK 回退 ICC:属于“文件输入”环节的全局设置,只有一项,在设置窗口里填写文件名。程序目录下的
icc/目录用于存放这些 ICC 文件。 - 每个 Worker 的 preset:定义自己的输出 ICC、渲染意图、黑点补偿。
输入侧基本规则如下:
- RGB 输入:优先使用可读的内嵌 ICC;没有内嵌或内嵌无法读取时,按
sRGB处理。 - CMYK 输入:优先使用可读的内嵌 ICC;没有内嵌或内嵌无法读取时,使用全局 CMYK 回退 ICC;两者都没有时,直接拒绝处理,避免错误解释色彩空间。
- 因此 CMYK 回退 ICC 只在“CMYK 输入且没有可用内嵌 ICC”这一种情况下生效;它是文件输入层面的统一兜底,而不是逐 Worker 维护。
输出侧统一转换到驱动更容易接受的工作结果(RGB),再交给打印机驱动继续处理纸张、墨水和介质逻辑。这使得同一批任务可以针对不同机型、不同纸张、不同墨水方案,走不同的 preset 输出 ICC 组合,而输入侧的 CMYK 解释只需配置一次。
输出 ICC 必须是 RGB 配置文件。 渲染结果在送入 Windows 驱动前会统一栅格化为 RGB 位图,因此 preset 的输出 ICC 只能是 RGB 设备/工作空间配置文件(例如某台打印机的 RGB 特性文件或标准 RGB 工作空间)。如果填入的是 CMYK、灰度或 Lab 配置文件,程序会在处理该任务时直接报错并跳过,而不会输出错误颜色;输出 ICC 文件缺失或无法读取时也会给出明确提示。需要的 CMYK 处理应放在输入侧(内嵌 ICC 或全局 CMYK 回退 ICC)。
Workers 列表定义了实际参与生产的输出节点。每个 Worker 本质上对应一台打印机加一组运行参数,主要包括:
- 是否启用
- Worker 名称
- 打印机名称
- 当前 preset
- 速度
- 状态
其中“速度”并不是抽象权重,而是一个直接可理解的相对产能参数。你可以把它理解为“单位时间能完成的张数”。
例如:
- A 机速度 = 25
- B 机速度 = 5
那么 30 份任务会被分配成约 25 : 5,整体完成时间更接近各机同时结束,而不是某台机器明显拖尾。
如果实际速度、维护暂停或打印队列限流造成尾段不均衡,可以在设置中启用 尾段动态均衡。该机制不改变初始静态分配,只在某个 Worker 自己的静态队列已空、且空闲超过“空闲判定时间(秒)”后进入接手状态;后续只要重新空闲,就会继续接手其他 Worker 尚未发送到 Windows Spooler 的 1 份任务。
InkSwarm 还支持 Workers 方案组:
- 程序根目录下所有
Workers、Workers_*目录都可以作为独立方案组。 - 不同方案组可以对应不同纸张、不同介质、不同机群配置。
- GUI 中可以快速切换当前方案组。
InkSwarm 不试图取代打印机驱动的复杂参数,而是与驱动协同工作。
你可以在 GUI 中:
- 打开驱动首选项
- 打开打印机属性
- 导出当前驱动设定
导出的驱动设定会保存为 PrintUI 的 .dat 快照文件,并绑定到当前 preset。真正发送任务前,程序会先恢复对应的驱动快照,再执行打印动作。这样做有两个直接好处:
- 不同 preset 可以对应不同纸张/介质/质量设定。
- 即便多个 Worker 指向相似机型,也能保持独立、明确、可复现的驱动状态。
在设置面板中还提供 忽略页边距 选项。启用后,程序会尽量按整张物理纸面定位,不再主动为了打印机报告的不可打印边距留白,让满版设计更接近预期输出。
缩放模式 决定内容相对纸张的定位与缩放方式。它是一个全局设定(在设置面板中选择,作用于本次发送的所有 Worker),并且是绘制阶段的决定:它只改变图像在打印机设备上下文中的目标矩形,不改变已渲染的缓存位图,因此切换缩放模式不会让渲染缓存失效,也不会触发重新 RIP。
所有模式都会把内容居中放置;“适配区域”取决于 忽略页边距:启用忽略页边距时按整张物理纸面计算,否则按驱动报告的可打印区域计算。判定基准是内容的真实物理尺寸(毫米)换算到设备像素后的 1:1 大小。
四种模式:
- 实际尺寸(超出缩小) —— 默认且最稳妥。按文件真实物理尺寸(1:1)打印;只有当内容大于纸张时才等比缩小以适应,永不放大,保持毫米比例。
- 强制 100%(裁切溢出) —— 始终按精确 100% 物理尺寸打印,绝不缩放。若内容大于纸张,只打印居中部分,外圈被裁切。适用于需要严格保证毫米级尺寸准确的场景,例如边框略微超出标准纸张、但又必须保证成品尺寸精确。
- 适应纸张 —— 等比放大或缩小到刚好放进纸面,保持长宽比;整幅内容都可见,可能留白。
- 填满裁切 —— 等比缩放到铺满整张纸,保持长宽比;溢出部分被裁切,不留白边。
缩放模式与 自适应纸张方向 叠加时,先在缓存生成阶段完成旋转,再在打印阶段按缩放模式定位。设置面板中切换模式时会即时显示该模式的简要说明,便于在应用前确认其实际含义。
缓存机制是 InkSwarm 性能设计的重点。
对于同一个 Worker 处理同一个任务:
- 只会执行一次渲染与色彩转换。
- 渲染结果保存到本地缓存目录。
- 后续同任务的多份输出直接复用缓存,不再重复 RIP。
缓存 key 会综合以下因素生成:
- 输入文件签名(路径、大小、修改时间,并带内容校验)
- preset 的色彩链路(输出 ICC 内容、渲染意图、黑点补偿、DPI)
- 全局 CMYK 回退 ICC 的内容
- 方向选项
- RIP 精度限制
缓存 key 采用 ICC 内容而非文件名,因此即便替换了同名 ICC 文件,缓存也会感知到变化;同时配置完全一致的多个 Worker 会自动复用同一份缓存。只要其中任一关键条件变化,程序就会自动生成新的缓存,不会误用旧结果。
这个机制不仅节省 CPU 和内存,也显著减少了重复色彩转换和重复 PDF 渲染带来的不稳定因素。
InkSwarm 的日志分成三层,各自职责不同。
保存于 logs/ 目录,记录:
- 调度摘要
- Worker 状态变化
- 缓存使用情况
- 流程开始与结束
- 成功/失败任务统计
它的目标是让操作者看得懂当前系统正在做什么,而不是堆满底层细节。
同样位于 logs/ 目录,文件名为 debug.log。程序每次启动时会清除上一次的 debug.log,重新开始记录。
Debug 日志会写入更底层的信息,例如:
- 应用启动参数
- 设置读取结果
- 渲染缓存命中与重建
- ICC 转换链路
- 最终缓存图像尺寸
- 打印时的目标绘制尺寸与矩形
- 线程异常与未捕获异常
- Qt 消息
这份日志主要用于排查生产环境中的偶发问题和底层异常。
程序还会在 statistics/ 目录下按月生成 CSV,例如:
statistics/2026-04.csv
统计文件记录已经成功发送到 Windows Spooler 的张数;即使流程被手动停止、软件崩溃,或 CSV 被 Excel 打开锁定,程序也会先把每张成功记录写入 statistics/pending_runs/ 下的可恢复快照,之后再同步到按月 CSV。
- 任务启动时刻(精确到秒)
- 最后成功时刻
- 文件名
- 请求张数
- 成功张数
- 未完成张数
- 完成状态
- 运行 ID / 任务 ID
它按任务列表条目逐行记录,而不是按 Worker 维度拆分。也就是说,一个列表里有 3 个文件,最终统计就是 3 行;中途停止时,已经成功送入 Spooler 的张数也会体现在对应行的“成功张数”里。
为防止断电或崩溃导致统计文件损坏,pending 快照和 CSV 都采用原子替换方式落盘。CSV 如果暂时被 Excel 锁定,pending 快照会保留,程序会在下次启动或下次流程结束时重试同步。
InkSwarm 当前已经具备生产可用的基本形态,但它依然保持着一个很清晰的目标:
把复杂、多机、可控的打印流程,尽量变成一条稳定、透明、容易排查的生产链。
