# A1 Swap Mod Packer 当前版本:**v0.6.0** A1 Swap Mod Packer 是一个开源的 3MF 打包工具,专为 Bambu Lab A1 SwapMod 工作流设计。 它接收一个或多个 A1 切片后的 `.3mf` 文件,根据设定份数重复其面板 G-code,插入外部 SwapMod 弹射/换板 G-code 块,并输出一个新的打包 `.3mf` 文件,可直接发送至打印机。 ![A1 Swap Mod Packer 截图](https://images-tfb361lw6pyvz9bxue3s.oss-cn-chengdu.aliyuncs.com/obsidian/20260728140250243.png) ![](https://images-tfb361lw6pyvz9bxue3s.oss-cn-chengdu.aliyuncs.com/obsidian/20260728140421994.png) ## 注意事项 - 本项目不含任何闭源代码。所有功能均通过对比 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` 中的规则 |