618 lines
14 KiB
Markdown
618 lines
14 KiB
Markdown
# A1 Swap Mod Packer
|
||
|
||
当前版本:**v0.6.0**
|
||
|
||
A1 Swap Mod Packer 是一个开源的 3MF 打包工具,专为 Bambu Lab A1 SwapMod 工作流设计。
|
||
|
||
它接收一个或多个 A1 切片后的 `.3mf` 文件,根据设定份数重复其面板 G-code,插入外部 SwapMod 弹射/换板 G-code 块,并输出一个新的打包 `.3mf` 文件,可直接发送至打印机。
|
||
|
||

|
||
|
||
<img src="docs/a1_swapmod_realphoto.webp" width="50%" />
|
||
|
||
## 注意事项
|
||
|
||
- 本项目不含任何闭源代码。所有功能均通过对比 3MF 文件生成前后的状态独立实现。
|
||
- 目前仅在 Windows 10 上测试验证过。
|
||
- 生产环境使用前,请先在安全/简单的打印任务上测试生成的文件。
|
||
|
||
## 主要功能
|
||
|
||
- 拖放式批量打包 GUI。
|
||
- 可重复执行的自动化 CLI。
|
||
- 支持多个 `.3mf` 输入文件。
|
||
- 每个文件独立份数。
|
||
- 自动从 `Metadata/slice_info.config` 读取并汇总时间和耗材。
|
||
- 外部 SwapMod G-code 模板目录。
|
||
- 可编辑 G-code 补丁文件。
|
||
- 可选通过 `M73 R...` 编码剩余时间板号。
|
||
- GUI 中选中文件缩略图预览。
|
||
- 最多 9 个不同输入文件的预览图合成,带 `{plates} P` 绿色标签。
|
||
- 合并模式:所有输入行合并为一个打包 3MF。
|
||
- 独立批处理模式:每行输入各生成一个独立打包 3MF。
|
||
- zlib-ng Deflate ZIP 压缩,默认级别 7。
|
||
- GUI 设置保存到程序目录的 `settings.json`。
|
||
|
||
## 源码安装
|
||
|
||
推荐 Python 3.13 及以上(Nuitka 4.x 对 3.14 仅实验性支持)。Python 3.10+ 亦可使用。
|
||
|
||
安装依赖:
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
当前运行时依赖:
|
||
|
||
| 依赖 | 用途 |
|
||
|---|---|
|
||
| `PySide6` | GUI 界面、拖放表格、文件对话框、缩略图预览、设置界面 |
|
||
| `Pillow` | 读取和合成输出 3MF 中的 PNG 预览图,包括 `{plates} P` 标签 |
|
||
| `zlib-ng` | ZIP Deflate 压缩后端,用于写入压缩 3MF 并控制压缩级别 |
|
||
|
||
当前 Python 源码版本不需要 Java 运行时、Bambu Studio SDK、外部压缩工具或加密/模板解码器。
|
||
|
||
启动 GUI:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.gui
|
||
```
|
||
|
||
或
|
||
|
||
```bash
|
||
python run_gui.py
|
||
```
|
||
|
||
启动 CLI:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli --help
|
||
```
|
||
|
||
或
|
||
|
||
```bash
|
||
python run_cli.py
|
||
```
|
||
|
||
查看版本:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli --version
|
||
```
|
||
|
||
## 构建 Windows 可执行文件
|
||
|
||
仓库包含 Windows 构建脚本:
|
||
|
||
```cmd
|
||
build_win.cmd
|
||
```
|
||
|
||
脚本使用 Nuitka onefile 模式,生成如下便携发布目录:
|
||
|
||
```text
|
||
build/onefile/
|
||
```
|
||
|
||
预期输出:
|
||
|
||
```text
|
||
build/onefile/
|
||
a1packer.exe
|
||
a1packer-cli.exe
|
||
gcode_patches.ini
|
||
swap_gcode/
|
||
x.png 输出预览图示例
|
||
settings.json 可选;GUI 保存设置后自动生成
|
||
```
|
||
|
||
外部资源刻意保留在可执行文件外部。不要将这些文件打包进 onefile 二进制:
|
||
|
||
```text
|
||
swap_gcode/
|
||
gcode_patches.ini
|
||
settings.json
|
||
```
|
||
|
||
打包为 exe 时,程序会从 exe 所在目录解析这些路径。
|
||
|
||
### Windows 构建要求
|
||
|
||
已验证的构建环境:
|
||
|
||
- Windows 10。
|
||
- Python 3.10 及以上。
|
||
- 虚拟环境 `.venv/`。
|
||
- `requirements.txt` 中的运行时依赖。
|
||
- Nuitka 支持 onefile 模式。
|
||
- Microsoft C++ Build Tools / Visual Studio Build Tools(含 MSVC 编译器和 Windows SDK)。
|
||
|
||
在干净的虚拟环境中安装 Python 依赖:
|
||
|
||
```cmd
|
||
py -3.13 -m venv .venv
|
||
.venv\Scripts\python.exe -m pip install --upgrade pip
|
||
.venv\Scripts\python.exe -m pip install -r requirements.txt
|
||
.venv\Scripts\python.exe -m pip install "Nuitka[onefile]"
|
||
```
|
||
|
||
然后执行:
|
||
|
||
```cmd
|
||
build_win.cmd
|
||
```
|
||
|
||
构建脚本执行两次 Nuitka 编译:
|
||
|
||
- GUI:`run_gui.py` → `build/onefile/a1packer.exe`
|
||
- CLI:`run_cli.py` → `build/onefile/a1packer-cli.exe`
|
||
|
||
GUI 编译启用 PySide6 插件并包含当前界面所需的 Qt 插件组:
|
||
|
||
```text
|
||
platforms,imageformats,styles,iconengines
|
||
```
|
||
|
||
### 构建后验证
|
||
|
||
发布目录前,先确认 CLI 能识别外部资源:
|
||
|
||
```cmd
|
||
build\onefile\a1packer-cli.exe --version
|
||
build\onefile\a1packer-cli.exe list-swap-gcode
|
||
```
|
||
|
||
第二条命令应列出:
|
||
|
||
```text
|
||
build/onefile/swap_gcode/
|
||
```
|
||
|
||
中的文件。
|
||
|
||
同时启动一次 `build/onefile/a1packer.exe`,确认:
|
||
|
||
- 换盘 G-code 下拉框列出已复制的模板。
|
||
- 修改 GUI 选项会创建或更新 `build/onefile/settings.json`。
|
||
- 首次启动前 `settings.json` 不存在时程序仍能正常运行。
|
||
|
||
## 换盘 G-code 模板
|
||
|
||
GUI 会自动扫描以下固定目录:
|
||
|
||
```text
|
||
swap_gcode/
|
||
```
|
||
|
||
纯 UTF-8 文本文件直接读取。当前扫描器接受以下后缀:
|
||
|
||
```text
|
||
.gcode
|
||
.nc
|
||
.ngc
|
||
.txt
|
||
```
|
||
|
||
当前源码版本不解码加密的或厂商模板的 G-code 归档。
|
||
|
||
GUI 中使用方法:
|
||
|
||
1. 将模板文件放入 `swap_gcode/`。
|
||
2. 点击 **换盘 G-code** 旁的 **刷新**。
|
||
3. 从下拉框中选择模板。
|
||
|
||
## 可编辑 G-code 补丁
|
||
|
||
GUI 和 CLI 都读取固定补丁文件:
|
||
|
||
```text
|
||
gcode_patches.ini
|
||
```
|
||
|
||
默认规则:
|
||
|
||
```ini
|
||
[patch.a1_start_y]
|
||
enabled = true
|
||
flag = G0 X128 F30000
|
||
find = G0 Y254 F3000
|
||
replace = G0 Y250 F3000 ; Patched
|
||
max_count = 1
|
||
```
|
||
|
||
含义:
|
||
|
||
- 从可选的 `flag` 行之后开始查找。
|
||
- 将第一个匹配 `find` 的行替换为 `replace`。
|
||
- 最多替换 `max_count` 次。
|
||
|
||
可在 GUI 中通过 **G-code 补丁** 复选框禁用,或编辑 INI 文件并保持启用。
|
||
|
||
换板插入标记也可编辑:
|
||
|
||
```ini
|
||
[swap]
|
||
insert_before_marker = ;=====printer finish sound=========
|
||
```
|
||
|
||
## GUI 使用指南
|
||
|
||
### 输入 3MF 文件
|
||
|
||
输入表格支持:
|
||
|
||
- **添加 3MF**:选择一个或多个 `.3mf` 文件。
|
||
- 拖放 `.3mf` 文件到表格中。
|
||
- 拖放文件夹到表格中。GUI 会添加该文件夹内所有顶层 `.3mf` 文件。
|
||
- **移除**:移除选中行。
|
||
- **全部移除**:清空全部输入列表。
|
||
- **上移 / 下移**:调整输入顺序。
|
||
- **应用默认份数至选中行**:将当前默认份数覆盖到选中行。
|
||
|
||
列说明:
|
||
|
||
- **3MF 文件**:源文件路径。
|
||
- **份数**:该源文件重复的次数。
|
||
- **时间**:预估打印时间 × 份数。
|
||
- **耗材**:预估耗材用量 × 份数。
|
||
|
||
时间和耗材数据读取自:
|
||
|
||
```text
|
||
Metadata/slice_info.config
|
||
```
|
||
|
||
如果源 3MF 缺少此元数据,GUI 显示"未知"。
|
||
|
||
输入列表下方的汇总行显示当前表格的总板数、预估时间和耗材。
|
||
|
||
右侧缩略图面板显示选中输入文件的活动面板预览(若 3MF 中包含)。
|
||
|
||
### 构建 3MF 按钮
|
||
|
||
**构建 3MF** 按钮位于输入列表右下方,便于快速批量操作。
|
||
|
||
正常合并模式下,一次点击生成一个包含所有输入行的输出 3MF。
|
||
|
||
独立批处理模式下,一次点击为每行输入各生成一个输出 3MF。
|
||
|
||
### 换盘 G-code
|
||
|
||
选择插入到每个重复面板中的弹射/换板 G-code 块。
|
||
|
||
下拉框内容来自:
|
||
|
||
```text
|
||
swap_gcode/
|
||
```
|
||
|
||
按钮:
|
||
|
||
- **刷新**:重新扫描目录。
|
||
- **打开文件夹**:打开模板目录。
|
||
|
||
### 新输入的默认份数
|
||
|
||
设置添加到或拖入的新文件的默认份数。
|
||
|
||
这不会自动更改已有行。对已有行使用 **应用默认份数至选中行**。
|
||
|
||
> 提示:所有数值输入框均为纯数字输入(QLineEdit),无上下箭头,可直接键入任意数值。
|
||
|
||
### 热床降温
|
||
|
||
控制是否在 SwapMod G-code 块之前插入热床等待温度。
|
||
|
||
启用示例:
|
||
|
||
```gcode
|
||
M190 S45
|
||
```
|
||
|
||
禁用后,打包器不添加 `M190` 行。
|
||
|
||
### 换盘后等待时间
|
||
|
||
勾选框控制是否在换盘 G-code 块之后插入驻留时间。
|
||
|
||
默认 30 秒,可通过纯数字输入框(QLineEdit)调整:
|
||
|
||
```gcode
|
||
G4 P30000
|
||
```
|
||
|
||
### 剩余时间板号
|
||
|
||
启用后,打包器按以下公式偏移 `M73 ... R...` 剩余时间值:
|
||
|
||
```text
|
||
板号 × 100 小时 × 60 分钟
|
||
```
|
||
|
||
这使得 A1 剩余时间的百位能显示当前板号。
|
||
|
||
示例:
|
||
|
||
- 第 1 板:+6000 分钟
|
||
- 第 2 板:+12000 分钟
|
||
- 第 3 板:+18000 分钟
|
||
|
||
### 最后换盘
|
||
|
||
启用后,换板/弹射块也会插入到最后一个重复面板之后。
|
||
|
||
禁用后,最后一个重复面板正常结束,不执行换盘 G-code 块。
|
||
|
||
### G-code 补丁
|
||
|
||
应用来自以下文件的规则:
|
||
|
||
```text
|
||
gcode_patches.ini
|
||
```
|
||
|
||
**打开配置文件** 按钮打开该固定文件进行编辑。
|
||
|
||
### 3MF 元数据
|
||
|
||
选项:
|
||
|
||
- **累加预测和耗材用量(默认)**
|
||
使用所有重复面板的总和更新第一块面板的元数据。从统计角度看更合理,适合 SwapMod 场景。
|
||
|
||
- **保留原始预测和重量**
|
||
保持基础 3MF 中 `slice_info.config` 的预测和重量值不变。
|
||
|
||
### 预览图处理
|
||
|
||
默认情况下,输出 3MF 保留基础归档中对应当前输出面板的预览成员,并用以下内容重写这些 PNG 预览:
|
||
|
||
- 最多 9 个不同输入文件的预览图合成;
|
||
- 一个简短的绿色标签(如 `5 P`),施加在最终合成图上。
|
||
|
||
如果预览图缺失或无法读取,打包器保留可用基础预览,仍尝试施加面板标签。
|
||
|
||
CLI 可通过以下选项禁用预览重写:
|
||
|
||
```bash
|
||
--no-preview-label
|
||
```
|
||
|
||
### 批处理模式
|
||
|
||
#### 合并模式
|
||
|
||
默认行为。
|
||
|
||
所有输入行打包为一个输出文件。
|
||
|
||
示例:
|
||
|
||
```text
|
||
A.3mf 份数 2
|
||
B.3mf 份数 3
|
||
```
|
||
|
||
输出:
|
||
|
||
```text
|
||
一个打包 3MF,包含 A, A, B, B, B
|
||
```
|
||
|
||
#### 独立批处理模式
|
||
|
||
启用时,GUI 显示说明弹窗。
|
||
|
||
每行输入被视为独立构建。
|
||
|
||
示例:
|
||
|
||
```text
|
||
A.3mf 份数 5
|
||
B.3mf 份数 5
|
||
C.3mf 份数 5
|
||
```
|
||
|
||
输出:
|
||
|
||
```text
|
||
5 Plates - A.3mf
|
||
5 Plates - B.3mf
|
||
5 Plates - C.3mf
|
||
```
|
||
|
||
此模式用于快速将大量独立的单板 3MF 文件批量转换为多份数 SwapMod 包。
|
||
|
||
GUI 并行构建这些独立输出,并发数受 CPU 核心数及安全上限限制。
|
||
|
||
它**不会**将所有输入合并为一个文件。
|
||
|
||
### 输入处理
|
||
|
||
- **添加输入时跳过重复文件路径**
|
||
防止意外多次添加同一路径。
|
||
|
||
### 构建成功后
|
||
|
||
- **清空输入列表**
|
||
构建成功后清空表格。在独立批处理模式下,仅当所有输出构建成功后才会清空。
|
||
|
||
### 输出目录
|
||
|
||
如果此字段为空:
|
||
|
||
- 合并模式写入第一个输入文件同目录。
|
||
- 独立批处理模式将每个输出写入各自输入文件同目录。
|
||
|
||
如果选择了目录,所有输出都写入该目录。
|
||
|
||
### 输出文件名规则
|
||
|
||
默认规则:
|
||
|
||
```text
|
||
{plates} Plates - {sources}.3mf
|
||
```
|
||
|
||
点击规则字段旁的 `?` 按钮显示标记帮助。
|
||
|
||
可用标记:
|
||
|
||
| 标记 | 含义 |
|
||
|---|---|
|
||
| `{source}` | 第一个输入文件的文件名(不含 `.3mf`) |
|
||
| `{sources}` | 源文件摘要。单个源使用其文件名;多个源则显示为 `first_source_and_N_more` |
|
||
| `{plates}` | 本输出中的总板数 |
|
||
| `{copies}` | 本输出中的总份数 |
|
||
| `{date}` | 当前日期,格式 `YYYYMMDD` |
|
||
| `{time}` | 当前时间,格式 `HHMMSS` |
|
||
|
||
在独立批处理模式下,标记按每行输入单独计算。
|
||
|
||
示例:
|
||
|
||
```text
|
||
{plates} Plates - {sources}.3mf
|
||
SwapMod - {source} - x{copies}.3mf
|
||
{date}_{time}_{source}.3mf
|
||
```
|
||
|
||
## GUI 设置
|
||
|
||
GUI 将设置写入程序目录:
|
||
|
||
```text
|
||
settings.json
|
||
```
|
||
|
||
这是有意为之,以便便携式解压目录或打包的 `.exe` 版本能将选项保持在应用程序旁边。
|
||
|
||
保存的选项包括:
|
||
|
||
- 当前选中的换盘 G-code 文件。
|
||
- 默认份数。
|
||
- 热床降温设置。
|
||
- 换盘后等待时间。
|
||
- 剩余时间板号开关。
|
||
- 最后换盘开关。
|
||
- G-code 补丁开关。
|
||
- 元数据模式。
|
||
- ZIP 压缩级别。
|
||
- 独立批处理模式。
|
||
- 输入处理选项。
|
||
- 构建成功后清空输入列表。
|
||
- 输出目录。
|
||
- 输出文件名规则。
|
||
|
||
## CLI 使用示例
|
||
|
||
列出可用的换盘 G-code 文件:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli list-swap-gcode
|
||
```
|
||
|
||
单源文件 × 5 份:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli build \
|
||
--item "SC05720_01.gcode(1).3mf" 5 \
|
||
--swap-gcode "a1_swap.gcode" \
|
||
--cool-bed 45 \
|
||
--wait 45 \
|
||
--show-plate-number \
|
||
-o "5 Plates - SC05720_01.gcode(1).3mf"
|
||
```
|
||
|
||
多源文件合并输出:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli build \
|
||
--item "A.3mf" 2 \
|
||
--item "B.3mf" 3 \
|
||
--swap-gcode "a1_swap.gcode" \
|
||
-o "5 Plates - A_and_B.3mf"
|
||
```
|
||
|
||
使用累加元数据模式:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli build \
|
||
--item "A.3mf" 5 \
|
||
--swap-gcode "a1_swap.gcode" \
|
||
--metadata-mode sum \
|
||
-o "5 Plates - A.3mf"
|
||
```
|
||
|
||
禁用 G-code 补丁:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli build \
|
||
--item "A.3mf" 5 \
|
||
--swap-gcode "a1_swap.gcode" \
|
||
--no-gcode-patches \
|
||
-o "5 Plates - A.3mf"
|
||
```
|
||
|
||
位置参数输入 + 统一份数:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli build \
|
||
"A.3mf" "B.3mf" \
|
||
--copies 2 \
|
||
--swap-gcode "a1_swap.gcode" \
|
||
-o "4 Plates - A_and_B.3mf"
|
||
```
|
||
|
||
指定换盘 G-code 目录和 ZIP 压缩级别:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli build \
|
||
--item "A.3mf" 5 \
|
||
--swap-gcode "a1_swap.gcode" \
|
||
--swap-gcode-dir "D:\SwapMod\swap_gcode" \
|
||
--zip-level 9 \
|
||
-o "5 Plates - A.3mf"
|
||
```
|
||
|
||
禁用最后换盘和预览标签重写:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli build \
|
||
--item "A.3mf" 5 \
|
||
--swap-gcode "a1_swap.gcode" \
|
||
--no-swap-after-final \
|
||
--no-preview-label \
|
||
-o "5 Plates - A.3mf"
|
||
```
|
||
|
||
禁用换盘后等待时间:
|
||
|
||
```bash
|
||
python -m a1_swap_mod_packer.cli build \
|
||
--item "A.3mf" 5 \
|
||
--swap-gcode "a1_swap.gcode" \
|
||
--no-eject-wait \
|
||
-o "5 Plates - A.3mf"
|
||
```
|
||
|
||
CLI 常用选项速查:
|
||
|
||
| 选项 | 含义 |
|
||
|---|---|
|
||
| `--version` | 打印当前版本 |
|
||
| `list-swap-gcode` | 列出换盘 G-code 目录中的文件 |
|
||
| `--item PATH COPIES` | 添加一个带独立份数的输入;可多次使用 |
|
||
| 位置参数 `inputs` + `--copies N` | 添加多个使用相同份数的输入 |
|
||
| `--swap-gcode-dir DIR` | 使用自定义换盘 G-code 目录 |
|
||
| `--no-bed-cooldown` | 不在换盘块前插入 `M190` |
|
||
| `--no-swap-after-final` | 最后一块盘后不执行换盘块 |
|
||
| `--no-eject-wait` | 不插入换盘后等待时间(`G4 P...` 行) |
|
||
| `--line-ending lf\|crlf` | 选择生成 G-code 的换行符;默认 `crlf` |
|
||
| `--zip-level 1-9` | zlib-ng Deflate 压缩级别;默认 `7` |
|
||
| `--no-preview-label` | 不重写预览图标签/合成图 |
|
||
| `--no-gcode-patches` | 不应用 `gcode_patches.ini` 中的规则 |
|