解构 PhotoCraft:纯 Rust 命令注册表统一 UI、CLI 与 MCP,PSD 兼容 307/309
解构 PhotoCraft:纯 Rust 命令注册表统一 UI、CLI 与 MCP,PSD 兼容 307/309
【免费下载链接】photocraftPhotoCraft: An open-source, photo editor written by scratch in pure Rust项目地址: https://gitcode.com/gh_mirrors/pho/photocraft
PhotoCraft(photocraft)是一个纯 Rust 从零(clean-room)实现的开源 Photoshop 重实现:图层、蒙版、调整图层、图层样式、文字、矢量、笔刷与真实 PSD 文件全部运行在一个原生应用中,当前处于 early alpha 阶段。它最具辨识度的工程决策是把所有编辑行为收敛到一个 500+ 命令的注册表:桌面 UI、CLI、JSON 控制通道与 MCP 服务器共用同一个Session::execute入口,命令 id 采用 Photoshop 风格命名(如layer.newAdjustmentLayer.invert)。本文以源码证据拆解这套命令引擎的接线方式、写时复制瓦片、PSD 兼容性的证明路径,以及构建、无头批处理与自动化通道的实际用法。读完你可以复现构建流程、用cargo xtask核查分层规则与语料测试,并用photocraft-cli完成无头批处理。
一、核心主张与验证路径
PhotoCraft 对外给出的四个核心主张,每一条都能在仓库内定位到验证物:
| 主张 | 含义 | 佐证位置 |
|---|---|---|
| 一切皆命令 | UI、CLI、JSON 控制通道、MCP 服务器调用同一批命令,你能点到的脚本就能做到 | crates/engine/src/lib.rs第 3–6 行文件头注释;crates/engine/src/commands.rs第 14–28 行CommandSpec |
| 真实 PSD 兼容 | 打开、编辑、保存带图层的 PSD/PSB,重存后渲染一致 307/309(psd-tools 集) | crates/io/tests/it/corpus.rs;crates/psd/README.md |
| 原生且快 | wgpu GPU 合成器、写时复制(copy-on-write)瓦片、多线程滤镜 | crates/raster/src/lib.rs第 1–8 行;crates/gpu/src/compose.wgsl |
| 编译期分层 | 24+ crate 的依赖方向在构建工具中强制,低层 crate 不得依赖 UI 工具链 | xtask/src/layers.rs第 35–107 行;book/src/architecture/crates.md |
二、命令注册表与写时复制瓦片:核心机制拆解
2.1 命令引擎:把"编辑行为"从 UI 中抽离
设计意图写在crates/engine/src/lib.rs第 3–6 行:"每一个用户可见操作都是一条带稳定 id 与 JSON 参数的命令,每个前端都走同一个Session::execute入口。这就是 UI 可替换、应用完全可脚本化的原因。"
实现路径上,crates/engine/src/commands.rs第 14–28 行定义了命令的最小结构CommandSpec:id、label、菜单位置、默认快捷键、参数说明(一段人/Agent 可读的 JSON 描述)、启用条件谓词enabled、执行体run、是否记入 journal(用于 Actions 录制)。command_specs()(第 138 行)返回全部静态命令表,其中仅调整类命令就在crates/engine/src/commands.rs第 1418–1464 行循环派生出两条:layer.newAdjustmentLayer.<kind>(调整图层)与image.adjustments.<kind>(直接作用于像素),16 个调整种类由此得到 32 条命令。
统一入口Session::execute(crates/engine/src/lib.rs第 692–698 行)接受任意可选参数"coalesce":连续同 key 的编辑并入一个历史步骤,对应 Photoshop"一整个打字会话只产生一个 Edit Type Layer 步骤"的行为(第 686–688 行注释)。错误语义集中在EngineError(第 156–177 行):UnknownCommand、Disabled(带原因文本)、BadParams、NoDocument、NoLayer、Cancelled,脚本调用方可以精确区分"命令不存在"与"现在不允许执行"。Session本身(第 470–553 行)持有打开的文档列表、工具状态(ToolState,含BrushSettings)、命令日志journal、剪贴板、色彩管理状态与智能对象链接。
这条架构的直接后果是自动化不需要第二套实现:MCP 服务器与 JSON 通道列出的就是command_specs()本身(crates/automation/src/headless.rs第 365 行),命令列表附带disabledReason与needsDocument字段(crates/engine/src/commands.rs第 146–157 行),Agent 可以据此判断"先打开文档"还是"缺少选区"。
2.2 写时复制瓦片:让撤销便宜、大画布变轻
Surface是 256×256 瓦片的无限平面(crates/raster/src/lib.rs第 1–8 行注释):缺失瓦片按面默认像素读取(图层透明、"Reveal All" 蒙版白色),瓦片以Arc共享(Surface结构,第 133–138 行:BTreeMap<TileCoord, Arc<Tile>>)。于是克隆一个 surface 的代价是 O(瓦片数) 而非 O(像素数),修改只复制被触及的瓦片——撤销快照、后台任务与自动保存都建立在这个不变量上。
与常见实现的差异在边界处理:所有瓦片分配都是可失败的(Tile::try_filled/try_clone,第 45–66 行),内存不足返回AllocationError::NotEnoughMemory并向上映射为EngineError(crates/engine/src/lib.rs第 181–185 行,文档未被修改),而不是 panic。这个 crate 同样forbid(unsafe_code)并 deny 一切 panic 系 lint(第 7–8 行)。
三、能力全景与源码映射
| 能力域 | 覆盖范围(关键词级) | 实现位置 |
|---|---|---|
| 调整与图层样式 | 16 种调整图层(Curves/Levels/Vibrance/Color Lookup…);Drop Shadow、Outer Glow、Bevel & Emboss、Stroke、Pattern Overlay | 命令派生:crates/engine/src/commands.rs第 1418–1464 行;参数:crates/engine/src/adjust_params.rs;合成:crates/compose/src/adjust.rs |
| 选区与滤镜 | Quick/Object Selection、Select Subject;Gaussian/Motion/Smart Blur、Twirl、Oil Paint;大半径 running-sum 盒式卷积 | crates/algo/src/segment/;crates/engine/src/smartselect_cmds.rs;crates/algo/src/blur.rs第 109–160 行 |
| 笔刷引擎 | Shape Dynamics、Scattering、Wet Edges、Brush Pose、压感/倾斜/旋转驱动、确定性可重放笔画 | crates/paint/;引擎侧BrushSettings见crates/engine/src/lib.rs第 154 行 |
| 文字与矢量 | 点/段落文字、Character/Paragraph 控制;钢笔、形状图层、并/减/交/排布尔运算、PSD 形状 116/116 像素一致 | crates/text/、crates/engine/src/type_cmds.rs;crates/vector/、crates/engine/src/vector_cmds.rs |
| 格式读写 | PSD/PSB、带图层 TIFF、PNG/JPEG/WebP/EXR/HDR、.pcraft;PDN/XCF/KRA/SVG 可读,HEIC 只读 | crates/codecs/(能力矩阵见crates/codecs/README.md)、crates/format/、crates/psd/ |
| 色彩与合成 | RGB/Grayscale/CMYK/Lab、8/16/32 位、ICC 四渲染意图、GPU 软打样;CPU 合成器为参考 oracle | crates/cms/、crates/color/;crates/compose/与crates/gpu/互测 |
| 自动化通道 | 命令列表/执行、离屏截图、MCP、批处理 action | crates/automation/src/{bridge,rpc,security,workspace}.rs;apps/photocraft-cli/src/ |
两个值得注意的实现细节。其一,README 声称"3.6 MP 图像上半径 180 的高斯模糊不到一秒",其实现依据是crates/algo/src/blur.rs:小半径用精确卷积核,大半径分解为沿各轴的 running-sum 盒式多次卷积(第 109、135、156 行),跨所有核心并行。其二,图层混合模式为 27 种 Photoshop 模式加 6 种 Paint.NET 变体,BlendMode在crates/color中定义,未知模式键在 PSD 解析中以Unknown([u8;4])原样保留而非丢弃。
四、质量证据链:PSD 兼容性测试方法论与解析器边界
PhotoCraft 区分两个不同强度的承诺,混谈会高估其能力。
逐字节往返只对独立photocraft-psdcrate 成立:它不经过文档模型,纯解析加回写,PsdFile::from_bytes(b)?.to_bytes() == b对未修改文件成立(crates/psd/README.md第 13 行)。机制是:通道数据保留原始编码,未知块与资源存为 raw,tagged block 的 padding(2 字节还是 4 字节对齐)在可变处被精确记录。经文档模型打开再重存的文件则不保证字节相同——image resources、layer records 与合成图会被重写——但保证渲染一致:psd-tools 测试集 309 个文件中 307 个、ag-psd/psd-tools 混合集 170 个中 169 个重存后与源文件渲染一致(README.md第 224 行;断言逻辑在crates/io/tests/it/corpus.rs)。
crates/io/tests/it/corpus.rs第 68–80 行给出了判定阈值:oracle 比较容差PASS_TOL = 2/255,导出再导入的往返容差ROUNDTRIP_TOL = 1/255;当 Photoshop 未写合并图时,退回用文件内嵌缩略图作 oracle,要求均值误差 ≤ 3/255 且 ≤ 2% 像素偏差超过 24/255。语料按 pin 版本加 sha256 拉取(xtask/src/corpus_pins.rs),语料缺失时测试失败而非跳过。测试总量 README 声称超过 1,700 个,覆盖 PSD 往返、合成器生成器与多位深检查。
解析器安全边界是兼容性承诺的另一半(crates/psd/README.md第 7 行):解析永不 panic,维度上限 300,000,分配量对照剩余输入检查,单次解码上限MAX_DECODED_BYTES(64 位 8 GiB),描述符嵌套深度 ≤ 64,整个 crateforbid(unsafe_code)且可构建到wasm32-unknown-unknown。测试面包括截断扫描(每个前缀必须返回Err)、随机字节 proptest(永不 panic)、PackBits 边界与 8/16/32 位预测已知向量;fuzz 骨架在crates/psd/fuzz/,以cargo +nightly fuzz run parse运行。规范歧义(如 tagged block padding 检测算法、PSB 8 字节长度键列表)作为显式决策记录在crates/psd/README.md的 "Spec ambiguities and decisions" 一节。
五、构建运行步骤与 CLI 批处理用法
构建前提:Rust 1.95+、edition 2024(Cargo.toml第 8–10 行)。
git clone https://gitcode.com/gh_mirrors/pho/photocraft cd photocraft cargo run --release -p photocraft -- image.psd # 桌面应用 cargo test --workspace # 测试套件photocraft-cli的子命令面(apps/photocraft-cli/src/lib.rs第 52–61 行):
| 子命令 | 作用 |
|---|---|
convert <in> <out> | 格式互转(--format、--quality、--tiff-layers) |
info <file> | JSON 输出文档尺寸、模式、位深、图层树 |
run <file> | 打开后按序执行引擎命令再保存(--cmd+--params、--out) |
batch | 对目录内图像套用 action 列表(--actions、--in、--out) |
commands | 列出命令注册表(--json、--filter) |
mcp/serve | stdio MCP 服务器;JSON 行协议常驻会话(--port) |
无头批处理示例可直接复制:
photocraft-cli run wave.psd \ --cmd filter.sharpen.smartSharpen --params '{"amount":80}' \ --cmd layer.newAdjustmentLayer.curves --params '{"points":[[0,0],[64,48],[192,212],[255,255]]}' \ --out wave-final.png photocraft-cli batch --actions grade.json --in ./raw --out ./graded自动化通道的鉴权与边界:桌面端控制通道(photocraft --control)仅限回环,TCP 连接的首个请求必须是auth方法,token 为 64 位十六进制(crates/automation/src/security.rs第 12–15 行);文件访问受AuthorizedWorkspace的读/写根目录白名单约束(crates/automation/src/workspace.rs)。引擎侧对应Session::authorize钩子(crates/engine/src/lib.rs第 516–520 行):不可信会话(MCP、控制通道)装上与顶层请求相同的命令级鉴权,本地 UI 与photocraft-cli run不设限。协议细节见docs/control-protocol.md与book/src/automation/security-model.md。
平台安装要点:macOS/Windows/Linux/FreeBSD/Web 安装器随 release 发布;Linux 可选 AppImage、.deb、.rpm、tarball、Flatpak;Web 为静态站(packaging/web/package.sh),构建产物超过 24 MiB 即失败。
六、架构与工程决策
分层模型(book/src/architecture/crates.md,规则引擎在xtask/src/layers.rs第 35–76 行):
| 层 | 组件 | 职责 |
|---|---|---|
| L0 | geom、cms、color、raster | 几何、ICC、颜色/混合数学、COW 瓦片 |
| L0 独立 | psd、codecs、raw、affinity | 格式解析/编码,不依赖其他 workspace crate |
| L1 | doc | 纯数据文档:图层、蒙版、效果、文字、矢量 |
| L2 | ops、paint、algo、text、vector | 历史操作、绘制、成像算法、文字、路径 |
| L3 | compose、gpu、format | CPU 合成、wgpu 合成、.pcraft 持久化 |
| L4 | io、plugins、viewport等 | 文档模型与外部格式间的导入导出 |
| L5 | engine | Session、命令注册表、校验、历史集成 |
| L6 | ui-egui、automation | egui 壳、无头自动化、MCP、活动桥接 |
三个关键工程决策。双合成器互测:CPU 合成器(crates/compose/)是参考 oracle,wgpu 合成器(crates/gpu/,着色器crates/gpu/src/compose.wgsl)把画布放到 GPU 上,gpu在层内被约束只能依赖compose(xtask/src/layers.rs第 82 行INTRA_LAYER_ORDER),两者对拍。编译期依赖约束:UI_MIN_LAYER = 6(第 107 行),L6 以下任何 crate 依赖 egui/eframe/winit/rfd 即被cargo xtask layers拒绝;新 crate 必须先登记到xtask/src/layers.rs。WASM 体积预算:wasm-releaseprofile(Cargo.toml第 104–176 行)默认opt-level = "z"+ fat LTO,但把像素路径 crate(raster、color、paint)钉在 3,因为滤镜在浏览器里仍按像素运行;packaging/web/package.sh第 38 行设 24 MiB 硬门禁。整个 workspace 在[workspace.lints.rust]中unsafe_code = "forbid"(Cargo.toml第 71–72 行)。
七、客观边界:成熟度与已知缺口
PhotoCraft 不是日常专业工作的 Photoshop 替代品——这是项目在README.md第 309–310 行的自我声明。已知缺口:
- AI/生成式功能(Select Subject 等智能选区为本机算法,无云端);
- 约 15 个缺失工具;
- 排版与专业工作流深度不足;
- 插件不兼容(自有
crates/plugins/插件体系,非 Photoshop 插件)。
需要特别区分"接线"与"行为":docs/parity-checklist.md度量的是"每个 Photoshop 菜单项都接到了命令",不代表行为与 Photoshop 逐像素一致;逐维度的诚实评估在docs/target-app-parity.md,路线图在ROADMAP.md。
结语
PhotoCraft 把"编辑行为"收敛为带稳定 id 与 JSON 参数的命令,用Session::execute单一入口让 UI、CLI、JSON、MCP 共享执行路径;用 L0→L6 编译期分层、双合成器对拍与 COW 瓦片约束成像正确性与可维护性;用独立、无 unsafe、逐字节往返的photocraft-psd加上 307/309 语料对拍兑现 PSD 兼容承诺。它适合研究命令驱动型图形应用架构、photocraft-cli run/batch/mcp无头批处理、以及 WebAssembly 部署的早期评估;不适合作为专业修图的生产工具。进度追踪以docs/parity-checklist.md与docs/target-app-parity.md为准。
【免费下载链接】photocraftPhotoCraft: An open-source, photo editor written by scratch in pure Rust项目地址: https://gitcode.com/gh_mirrors/pho/photocraft
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考