LightroomForge
by cyZhu98
README.md
# LightroomForge · 影调锻造厂
**简体中文** · [English](README.en.md)
**An MCP server that gives AI agents full control of Adobe Lightroom Classic — catalog, develop engine, and masks.**
一个让 AI 智能体直接操控 Adobe Lightroom Classic 的 MCP 服务:目录检索、全套显影参数、几何蒙版与 AI 蒙版、预设、预览与导出。
> 名字由来:**Forge**(锻造)——影调不是套出来的,是一档一档锻出来的。LightroomForge = 在 Lightroom 里锻造影调的工作台。
---
## 目录
- [这是什么](#这是什么)
- [能力总览](#能力总览)
- [配合 skill 的自动化修图](#配合-skill-的自动化修图探索中)
- [系统架构](#系统架构)
- [环境要求](#环境要求)
- [安装](#安装)
- [快速上手](#快速上手)
- [工具参考](#工具参考)
- [蒙版体系详解](#蒙版体系详解)
- [已知限制](#已知限制)
- [故障排查](#故障排查)
- [开发与热更新](#开发与热更新)
- [目录结构](#目录结构)
- [致谢与许可](#致谢与许可)
---
## 这是什么
Lightroom Classic 本身不提供任何外部 API。LightroomForge 由两部分组成:
1. **Lightroom Lua 插件**(`lightroom-python-bridge.lrdevplugin`)——运行在 Lightroom 内部,通过**目录级直写**(`applyDevelopSettings`)绕过 UI 控制显影参数与蒙版;
2. **Python MCP 服务**(`mcp_server/`)——把插件能力包装成 167 个 MCP 工具,任何支持 MCP 的 AI 客户端(WorkBuddy、Claude Desktop、Cursor 等)都能直接调用。
关键设计:**能力在插件里,MCP 只是传输层**。即使 MCP 客户端出问题,直接用 `lightroom_sdk` 也能连上插件干活。
## 能力总览
| 模块 | 工具数 | 能力 |
|---|---:|---|
| `catalog_` | 15 | 搜索/选中照片、元数据、收藏夹、关键词、评分、**在修改照片模块打开**、导出 JPEG/TIFF、导入(受限,见[已知限制](#已知限制)) |
| `develop_` | 133 | 全套显影参数(曝光/对比/HSL/色彩分级/校准/锐化/降噪/镜头/效果/曲线)、批量读写、**蒙版全套**(几何 + AI 选区 + 图像蒙版)、自动色调/白平衡、Process Version |
| `preset_` | 4 | 列出/套用预设(转调 LR 原生预设引擎)、创建/删除预设(直写 XMP) |
| `preview_` | 5 | 单张/批量/对比预览渲染(JPEG) |
| `histogram_` | 3 | RGB / 亮度直方图分析(量化自检用) |
| `system_` | 4 | 连接状态、重连、热更新 |
| 顶层 | 3 | `lightroom_run_command`(任意 Lua 命令透传)、`list_capabilities`、`get_quick_start_guide` |
**特色能力:**
- **蒙版免手拖**:线性/径向/画笔蒙版的几何坐标可直写,配合 `zero/full` 两点式定位;
- **AI 蒙版**:天空/主体/背景/物体/人物可直接创建;**山脉/水面/人物等景观元素**可通过 `develop_create_image_mask` 直接写入(详见[蒙版体系](#蒙版体系详解));
- **本地参数自动换算**:蒙版调整参数直接传 UI 值(-100..100、曝光 EV),插件自动转换为目录量纲;
- **写入门哨兵**:LR 写锁拥挤时会静默丢弃写入——本项目所有写操作都会检测并显式报错,绝不假成功。
## 配合 skill 的自动化修图(探索中)
本项目提供的是**能力层**(MCP)——能读、能写、能建蒙版、能出预览。至于「怎么调」——诊断素材、定风格、编排蒙版、量化自检——属于 **skill 的方法论层**。两层合起来,可以做到一定程度的全自动修图。
下面就是作者本人跑出来的结果(北疆雪山湖,一张 RAW):

*原片(上)vs AI 全自动调色(下):天空压暗青、雪山去朦胧加锐、地面降曝、草地生成斜射光斑——全程零人工操作,参数由 AI 看片后自己决定。*

*MCP 直写落进 Lightroom 的蒙版组:天空暗青、雪山去朦胧加锐、地面压暗、草地光斑、山体受光、水面(`water-bridge-test`)——全部由 AI 创建,没有手拖一次。*
**需要坦白的是**:作者的 skill 目前仍在探索阶段,这套全自动流程的**最终效果离「出片」还有相当距离**——上图基本就是当前水平(甚至不算这张片子的最好版本),请把它当**能力验证**而不是作品来看。
所以这里只是**抛砖引玉**:能力层已经铺好、坑也踩平了,方法论那半张图,欢迎各位用自己的审美和方案去补。如果你跑出了更好的结果,非常欢迎回来分享。
## 系统架构
```
┌─────────────────┐ MCP(stdio) ┌──────────────────────┐
│ AI 客户端 │ ◄────────────► │ Python MCP Server │
│ (WorkBuddy 等) │ │ mcp_server/ (167 工具)│
└─────────────────┘ └──────────┬───────────┘
│ JSON over TCP(双 socket)
│ 端口见 lightroom_ports.txt
┌──────────▼───────────┐
│ Lightroom Lua 插件 │
│ 单/双 socket + 路由 │
└──────────┬───────────┘
│ LrApplication / LrDevelopController
┌──────────▼───────────┐
│ Lightroom Classic │
│ 目录库 .lrcat │
└──────────────────────┘
```
为什么是双 socket:Lightroom 的 `LrSocket` 单向,发和收必须分开两条连接;MCP 层用 `LRBRIDGE_PORT_FILE`(或自动发现)定位端口文件。
## 环境要求
| 项目 | 要求 |
|---|---|
| Lightroom Classic | 支持 SDK 的版本(本项目在 Windows / LR 2024-2026 系列实测;Process Version 15.4+) |
| Python | 3.10+(开发环境 3.13) |
| 操作系统 | Windows / macOS(路径逻辑已跨平台) |
| 依赖 | 见 `requirements.txt`:fastmcp、httpx、pydantic、pydantic-settings、Pillow、numpy |
## 安装
### 1. 安装 Lightroom 插件
Lightroom → `文件 → 增效工具管理器 → 添加`,选择 `lightroom-python-bridge.lrdevplugin` 文件夹。
或手动复制到:
- Windows:`%APPDATA%\Adobe\Lightroom\Modules\lightroom-python-bridge.lrdevplugin`
- macOS:`~/Library/Application Support/Adobe/Lightroom/Modules/lightroom-python-bridge.lrdevplugin`
### 2. 启动桥接
插件默认 **autoStart=true**:加载后自动启动、自动注册全部命令、零操作。
备用入口(自动启动失败时):`文件 → 增效工具额外功能 → Start Python Bridge`。
启动成功后插件目录内会生成 `lightroom_ports.txt`(两行端口号,send/recv)。
### 3. 安装 Python 依赖
```bash
cd LightroomForge-MCP
python -m venv .venv
# Windows
.venv\Scripts\python -m pip install -r requirements.txt
# macOS/Linux
.venv/bin/python -m pip install -r requirements.txt
```
### 4. 配置 MCP 客户端
在客户端的 MCP 配置里加入(路径换成本机实际路径):
```json
{
"mcpServers": {
"lightroom": {
"command": "D:/LightroomForge-MCP/.venv/Scripts/python.exe",
"args": ["D:/LightroomForge-MCP/run_mcp.py"],
"env": {
"LRBRIDGE_PORT_FILE": "D:/LightroomForge-MCP/lightroom_ports.txt"
}
}
}
}
```
> `LRBRIDGE_PORT_FILE` 可省略——客户端会自动在「项目根目录 / Lightroom Modules 插件目录」里找最新的端口文件。
### 5. 验证
```
system_status
```
返回 `connected: true` 即打通。若失败,看[故障排查](#故障排查)。
## 快速上手
典型会话(AI 视角):
```
1. catalog_search_photos(filename="DSC01445") → 找到照片 ID
2. catalog_open_in_develop(photo_ids=["140279"]) → 切到修改照片模块
3. develop_auto_tone() → 自动定调
4. develop_set_parameters({"Exposure2012": 0.3, "Contrast2012": 25, "Saturation": -12})
5. develop_create_linear_mask(...) → 天空/地面渐变
6. preview_generate(photo_id="140279", size=1024) → 拉预览看效果
7. histogram_analyze_current() → 量化自检
8. catalog_export_photos(photo_ids=[...], output_dir="/out", format="jpeg")
```
**用 SDK 直连**(不经过 MCP,适合脚本与调试):
```python
import asyncio
from lightroom_sdk import LightroomClient
async def main():
c = LightroomClient()
await c.connect()
r = await c.execute_command("develop.getSettings", {"photoId": "140279"}, timeout=30)
print(r)
await c.disconnect()
asyncio.run(main())
```
> `lightroom_run_command(command, params)` 可以把任意已注册的 Lua 命令直接透传——插件新增能力永远不需要等 Python 侧更新。
## 工具参考
### 目录 `catalog_*`
| 工具 | 说明 |
|---|---|
| `catalog_search_photos` | 按文件名/关键词/评级/日期搜索 |
| `catalog_get_selected_photos` | 当前选中照片 |
| `catalog_open_in_develop` | **UI 驱动类操作的前置**:把照片切到修改照片模块 |
| `catalog_export_photos` | 正式导出(JPEG/TIFF,尺寸/质量/目录) |
| `catalog_import_photos` | 导入(受限,快速失败,见已知限制) |
| `catalog_get_photo_metadata` / `_info` / `_collections` / `_keywords` / `_folders` | 元数据与组织结构 |
| `catalog_set_rating` / `catalog_add_keywords` | 写入元数据 |
### 显影 `develop_*`(133 个)
按类别(全部支持批量读写,`develop_batch_get_settings` / `develop_batch_apply_settings`):
| 类别 | 代表工具 |
|---|---|
| 基础 | `develop_adjust_exposure` / `_contrast` / `_highlights` / `_shadows` / `_whites` / `_blacks` / `_clarity` / `_texture` / `_dehaze` |
| 色彩 | `develop_adjust_temperature` / `_tint` / `_saturation` / `_vibrance`,HSL 三通道 × 8 色系 |
| 曲线 | `develop_set_tone_curve` / `_set_curve_points` / `_apply_s_curve` / `_get_curve_points` |
| 色彩分级 | `develop_adjust_color_grade_*`、分离色调 `_split_toning_*` |
| 校准 | `develop_adjust_calibration_*`(红/绿/蓝原色) |
| 细节 | `develop_adjust_sharpness` / `_sharpen_radius` / `_sharpen_detail` / `_sharpen_edge_masking`、亮度/彩色降噪 |
| 镜头 | 配置文件开关、手动畸变、暗角、去边 |
| 效果 | `develop_adjust_vignette*`、`develop_adjust_grain` |
| 管理 | `develop_get_current_settings` / `_set_parameters` / `_reset_all` / `_set_process_version` / `_auto_tone` / `_set_auto_white_balance` |
### 蒙版 `develop_*mask*`
| 工具 | 说明 |
|---|---|
| `develop_create_mask` | 通用创建(类型 + 参数) |
| `develop_create_linear_mask` / `_radial_*` | 经 `lightroom_run_command` 调用 `createLinearMaskWithGeometry` / `createRadialFilter` 可直写坐标几何 |
| `develop_create_ai_selection_mask` | AI 选区:subject / sky / background / objects / people(**异步计算,带 verified 字段**) |
| `develop_create_image_mask` | **景观元素蒙版**:山脉 50002 / 水面 50007 / 人物 20036 等,目录级直写 |
| `develop_list_masks` / `develop_get_selected_mask` / `develop_select_mask` / `develop_delete_mask` | 蒙版组读改删 |
| `develop_mask_diagnose` | 蒙版参数诊断 |
| `develop_activate_masking_mode` / `develop_reset_masking` | 面板与重置 |
### 预设 / 预览 / 直方图
| 工具 | 说明 |
|---|---|
| `preset_list` / `preset_apply` | 走 LR 原生预设引擎(支持自适应预设,AI 蒙版会被重新计算) |
| `preset_create` / `preset_delete` | 直写 `Develop Presets` 目录的 XMP(标量 + 曲线;蒙版组暂不支持写入) |
| `preview_generate` / `_batch` / `_comparison` | JPEG 预览渲染 |
| `histogram_analyze_current` / `_rgb` / `_luminance` | 直方图统计(p1/p50/p99、死黑/死白占比) |
## 蒙版体系详解
### 三种蒙版
| 类型 | 数据结构 | 创建方式 |
|---|---|---|
| 几何蒙版(线性/径向/画笔) | `What = "Mask/Gradient"` / `"Mask/CircularGradient"`,`zero/full` 两点定几何 | `develop.createLinearMaskWithGeometry` 等,直写 |
| AI 选区 | `What = "Mask/Image"` + `MaskSubCategoryID` | `develop_create_ai_selection_mask`(天空/主体等,UI 函数路径)或 `develop_create_image_mask`(景观元素,直写路径) |
| 范围蒙版(亮度/颜色) | RangeMask 字段 | `develop_create_mask` + 范围参数 |
### 景观元素子类型 ID(实测)
| ID | 元素 | ID | 元素 |
|---:|---|---:|---|
| `50002` | 山脉 | `50007` | 水面 |
| `20036` | 人物 | `50003/50004/50005` | 植被/地面等(来自 Adobe 自适应预设,未逐一验证) |
### 量纲约定(重要)
蒙版局部参数**直接传 UI 值**,插件自动换算:
- 曝光:EV(如 `0.5`),内部存 `EV/4`
- 其余(对比/清晰度/去朦胧/锐化/色温/饱和…):-100..100,内部存 `/100`
直接传目录量纲会被 LR 静默丢弃——这是本项目最常踩的坑,已在 `_build_correction_group` 统一处理。
### AI 蒙版的位图机制
AI 蒙版的位图不在设置文本里,而是存在 `<目录名>.lrcat-data`(RocksDB blob),通过 `MaskDigest` 引用:
- **带 digest 的组**(从既有蒙版克隆 `InputDigest`/`MaskDigest`/`FullMaskSize`/`Origin`/`ReferencePoint`/`WholeImageArea`)→ 即刻有效;
- **无 digest 的裸组** → 组存在、面板可见,但 LR **不会自动计算位图**(渲染、切蒙版工具、直写都不触发);
- 真正的「新照片自动算」走 **预设套用路径**:自适应预设(XMP)里不带 `MaskDigest`,套用时会触发 AI 重算。`preset_apply` 已打通这条路。
> 注意:LR 只在**启动时**扫描 `Develop Presets` 目录,新写入的预设需重启 LR 才能被 `preset_list` 看到。
### 蒙版组的读-改-写铁律
`getDevelopSettings()` **不返回** `MaskGroupBasedCorrections`。任何「读出全部组 → 追加 → 写回」的流程,读必须来自目录库:
```python
# 正确姿势(示意):从 .lrcat 解析现有组,再整表写回
groups = parse_groups_from_catalog(catalog_path, photo_id) # SQLite 读取 + 解析 Lua 表文本
groups.append(new_group)
await client.execute_command("develop.createImageMask",
{"subCategoryId": 50002, "existingGroups": groups})
```
`examples/create_ai_image_mask.py` 里有可用的解析器实现。
## 已知限制
| 限制 | 表现 | 替代方案 |
|---|---|---|
| `catalog_import_photos` / `catalog_create_virtual_copy` | 底层 API(`addPhoto`/`createVirtualCopies`)会 yield,与桥的任务模型不兼容,**快速失败**并给出指引 | 用 LR UI 导入 / 建虚拟副本;或磁盘复制 + 导入 |
| AI 蒙版裸组不重算 | 见上文 | 克隆 digest(同内容照片)或走自适应预设 |
| 预设目录仅启动时扫描 | 新预设不可见 | 重启 LR |
| 写锁拥挤静默跳过 | 已加哨兵:现在会显式报错 | 重载增效工具或重启 LR 清锁 |
| `preset_create` 不支持蒙版组 | 只写标量与曲线 | 用 LR 存预设,或用 `develop_create_image_mask` |
| 单客户端 | 桥接为单连接设计,多会话会互相抢 | 同一时间只用一个客户端 |
## 故障排查
### 桥接连不上
1. 看端口文件是否存在且新鲜:插件目录 / 项目根目录的 `lightroom_ports.txt`
2. 检查端口是否被占:`netstat -ano | findstr <端口>`(历史坑:迅雷等下载器抢占端口)
3. 重载插件:`增效工具管理器 → 重载增效工具`(桥会自动重启)
4. 插件日志:`%LOCALAPPDATA%\Adobe\Lightroom\Logs\LrClassicLogs\LightroomPythonBridge.log`
### 写入"成功"但目录没变化
写锁被僵尸任务侵占。本项目所有写 handler 都带 `executed` 哨兵,会报 `write gate skipped`——看到这个错误,**重载增效工具**;仍不行就重启 LR。
### 蒙版没效果
- 确认量纲:UI 值不是目录值;
- 确认 `MaskActive=true`、组 `CorrectionActive=true`;
- AI 蒙版确认 `MaskDigest` 存在(目录库查 `Adobe_imageDevelopSettings.text`)。
## 开发与热更新
```bash
# 启动
python -m mcp_server.main # 推荐
python run_mcp.py # 等价入口
```
**两部分的热更新策略:**
| 改动位置 | 生效方式 |
|---|---|
| `DevelopModule.lua` / `CatalogModule.lua` / `PreviewModule.lua` / `PresetModule.lua` | 调用 `system_reconnect` 前先 `system.reloadModules`(MCP 工具:`system_status` 同族命令 `system.reloadModules`),**零重启** |
| `PluginInit.lua` / `SimpleSocketBridge.lua` / `CommandRouter.lua` / `MessageProtocol.lua` | `增效工具管理器 → 重载增效工具` |
| `mcp_server/` Python 代码 | 重启 MCP 客户端 |
**新增 Lua 命令只需两步**:把 handler 写进对应模块 + 调 `system.reloadModules`——路由器有动态分发兜底(`module.fn` 约定从模块表找函数),不需要改注册表。
**调试**:Lua 侧 `logger:info(...)` → 插件日志;Python 侧 `logging` → 客户端 stderr;直连调试用 `lightroom_sdk`(见[快速上手](#快速上手))。
更深入的架构约定与踩坑记录见 [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md)。
## 目录结构
```
LightroomForge-MCP/
├── README.md 中文(默认)
├── README.en.md 英文
├── assets/ README 配图(前后对比、蒙版面板)
├── LICENSE Apache-2.0
├── NOTICE 上游项目致谢
├── requirements.txt
├── run_mcp.py MCP 服务入口
├── mcp_server/ 167 个 MCP 工具
│ ├── main.py 组合入口 + 能力清单
│ ├── servers/ system / catalog / develop / preview / presets
│ ├── shared/ 重连与命令执行
│ └── middleware/ 错误映射
├── lightroom_sdk/ TCP 客户端 SDK(可独立使用)
├── lightroom-python-bridge.lrdevplugin/
│ ├── PluginInit.lua 注册表 + 热更新 + 自动启动
│ ├── CommandRouter.lua 分发(含动态兜底)
│ ├── SimpleSocketBridge.lua 双 socket 主循环
│ ├── MessageProtocol.lua JSON 编解码
│ ├── CatalogModule.lua 目录 / 导入导出 / 切模块
│ ├── DevelopModule.lua 显影 + 蒙版(含 AI 图像蒙版)
│ ├── PreviewModule.lua 预览渲染
│ └── PresetModule.lua 预设
├── docs/
│ ├── API_REFERENCE.md
│ ├── API_DEVELOP_REFERENCE.md
│ └── DEVELOPMENT.md
└── examples/
├── preview.py
└── create_ai_image_mask.py
```
## 致谢与许可
本项目是合并版,吸收了两个上游开源项目的设计与代码:
- **lightroom-python-bridge**(noopz)——Lua 插件骨架、双 socket 桥、MCP 服务框架;
- **@mskalski/lightroom-mcp**——导入/导出/预设管理的 API 使用方式与任务模型经验。
合并、修复与新增(2026-10):任务模型适配、JSON 编解码修复、蒙版量纲换算、AI 图像蒙版直写、预设管理、热更新、写门哨兵、UUID 修复。
License: **Apache-2.0**(见 `LICENSE`),上手即用,改动请保留版权声明。
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues