Skip to content

Commit 0f81ad2

Browse files
committed
Merge branch 'dev'
2 parents e4af750 + 06f9fde commit 0f81ad2

13 files changed

Lines changed: 658 additions & 165 deletions

File tree

‎electron/main.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function setAppIcon(): void {
3131
function createWindow(): void {
3232
mainWindow = new BrowserWindow({
3333
width: 1600,
34-
height: 800,
34+
height: 850,
3535
minWidth: 900,
3636
minHeight: 500,
3737
resizable: true,

‎electron/services/agent/agentTools.ts‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getLayerMeta } from '../psd/layerCache'
44
import type { PsdLayerNode } from '../../../shared/types'
55
import {
66
exportGroups,
7+
exportSelection,
78
mutateLayers,
89
renameGroups,
910
setText,
@@ -278,6 +279,36 @@ export function createToolHandlers(deps: ToolDeps) {
278279
content: [{ type: 'text', text: JSON.stringify({ ...res.data, _log: res.log }) }],
279280
isError: !res.ok || res.data.err > 0
280281
}
282+
},
283+
284+
// 按选区导出:用户先在 Photoshop 中框选区域(矩形选框/套索等),然后调用此工具只导出选区范围内的目标图层。
285+
// 与 exportGroups 不同,此工具需要用户在 PS 中有激活的选区才会生效。
286+
async exportSelection(args: {
287+
targets: ExportTarget[]
288+
}): Promise<ToolResult> {
289+
const cur = getConversation(conversationId)!
290+
const targets = args.targets ?? []
291+
292+
if (targets.length === 0) {
293+
return {
294+
content: [{ type: 'text', text: '没有可导出的目标。请先用 search_layers 定位图层并传入 targets。' }],
295+
isError: true
296+
}
297+
}
298+
299+
const res = await exportSelection({
300+
targetPath,
301+
targets,
302+
x1: cur.opt1x,
303+
x2: cur.opt2x,
304+
trim: cur.optTrim,
305+
outputDir: cur.tmpDir
306+
})
307+
emit({ type: 'tool_result', name: 'export_selection', text: res.log.join('\n') })
308+
return {
309+
content: [{ type: 'text', text: JSON.stringify({ ...res.data, _log: res.log }) }],
310+
isError: !res.ok || res.data.err > 0
311+
}
281312
}
282313
}
283314
}

‎electron/services/agent/index.ts‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,26 @@ function buildTools(handlers: ReturnType<typeof createToolHandlers>): ToolDefini
185185
)
186186
}),
187187
execute: async (_id, params) => wrap(await handlers.exportGroups(params))
188+
}),
189+
defineTool({
190+
name: 'export_selection',
191+
label: '按选区导出图层',
192+
description:
193+
'导出用户在 Photoshop 中当前选区范围内的目标图层为 PNG。用户需先在 Photoshop 中用选区工具(矩形选框/套索/魔棒等)框选要导出的区域,然后调用此工具。' +
194+
'会读取 PS 中的激活选区,只导出选区内的内容。优先传 targets(来自 search_layers 的命中,含 psId/path/id/name)。' +
195+
'注意:选区必须在 Photoshop 中保持激活状态;如果选区已取消,请让用户重新框选。',
196+
parameters: Type.Object({
197+
targets: Type.Array(
198+
Type.Object({
199+
psId: Type.Optional(Type.Number({ description: 'PSD 原生图层 id(定位用)' })),
200+
path: Type.String({ description: '图层名链路径,如 根组/x默认/1' }),
201+
id: Type.String({ description: '路径式 id,如 0/2/1(psId 缺失时的回退)' }),
202+
name: Type.String({ description: '末端叶子图层/组名(命名用)' })
203+
}),
204+
{ description: 'search_layers 命中的导出目标列表' }
205+
)
206+
}),
207+
execute: async (_id, params) => wrap(await handlers.exportSelection(params))
188208
})
189209
]
190210
}
@@ -298,7 +318,13 @@ search_layers 会返回每个命中的 path(图层名链路径)与 psId(PSD 原
298318
- 改动会写回并保存到原始 PSD:重命名(rename_groups)、显示/隐藏/删除(mutate_layers)、修改文字(set_text)、合并图层组(merge_groups)作用在原稿上时,都必须先向用户说明并取得同意后才执行,不得擅自进行。删除与合并还会由系统再弹一次确认。
299319
- 为了导出而在临时副本上做的同类加工(改文字、合并、隐藏元素等),是导出流程的一部分,不改动原稿,无需征求同意,直接做。
300320
修改文字用 set_text(目标须为文字图层);合并图层组用 merge_groups(压平为单个图层,不可逆)。定位这些目标时优先用 search_layers 拿到的 psId,更精确。
301-
当前设计稿信息:\n${layerSummary}`
321+
当前设计稿信息:\n${layerSummary}
322+
323+
【按选区导出:export_selection】
324+
用户可能在 Photoshop 中手工框选了某个区域(矩形选框/套索等),然后说"导出这部分的某某图层"。
325+
此时使用 export_selection,其他规则(传 targets、命名、倍率等)与 export_groups 完全一致。
326+
关键区别:export_selection 会读取 PS 中当前激活的选区,只导出选区范围内的图层内容。
327+
使用前务必让用户确认 PS 中选区是激活状态。如果用户说"选区已经取消了/不再需要了",则用普通的 export_groups 导出全幅。`
302328

303329
addLog(
304330
conversationId,

‎electron/services/photoshop/operations.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,27 @@ export function mergeGroups(
106106
return runScript('merge-groups.jsx', { targetPath, targets })
107107
}
108108

109+
// 按选区导出:读取用户在 Photoshop 中的选区(选框/套索),只导出该选区范围内的目标图层。
110+
export function exportSelection(
111+
params: {
112+
targetPath: string
113+
targets: RawExportTarget[]
114+
x1: boolean
115+
x2: boolean
116+
trim: boolean
117+
outputDir: string
118+
}
119+
): Promise<JsxResult<{ files: string[]; matched: number; ok: number; err: number; outputDir: string }>> {
120+
return runScript('export-selection.jsx', {
121+
targetPath: params.targetPath,
122+
targets: toExportTargetParams(params.targets),
123+
x1: params.x1,
124+
x2: params.x2,
125+
trim: params.trim,
126+
outputDir: params.outputDir
127+
})
128+
}
129+
109130
// 单个导出目标:psId 用于在 PS 中精确定位(缺失则回退按名),
110131
// exportName 为最终文件名基名(叶子名_节点id,已做非法字符清洗)。
111132
// path/id 透传,便于导出后回写布局清单(无需从文件名反推)。

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ps2code",
3-
"version": "0.4.0",
3+
"version": "0.5.0",
44
"description": "帮助管理本地 PSD 设计稿,通过 Agent 对话调用 Photoshop 做图层操作与导出",
55
"author": "ps2code",
66
"main": "out/main/index.js",

‎scripts/jsx/README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ Bridge 在脚本顶部注入一个全局 `PS2CODE_PARAMS`(JSON 字符串)。各
1717
| `set-text.jsx` | 修改文字图层内容(目标须为文字图层)。psId 优先,回退按名定位第一个 |
1818
| `merge-groups.jsx` | 把图层组合并(压平)为单个图层,不可逆。psId 优先,回退按名定位第一个 |
1919
| `export-groups.jsx` | 导出匹配的图层组为 PNG(1x/2x/裁剪),移植自 backup/jsx/psd-group-exporter.jsx 的导出逻辑。重名组自动追加 `_01/_02` 后缀避免覆盖 |
20+
| `export-selection.jsx` | 导出用户 Photoshop 选区范围内的目标图层为 PNG。先读取选区边界,新建等尺寸临时透明文档,复制目标图层到临时文档,再裁剪到选区边界后导出(1x/2x/裁剪)。需要 PS 中有激活的选区(矩形选框/套索等均支持) |
2021

2122
## 参数示例
2223
- rename-groups:`{ "targetPath": "/a.psd", "rules": [{"from":"组 93","to":"组 193"}] }`
2324
- export-groups:`{ "targetPath": "/a.psd", "pattern": "^导出", "names": [], "x1": false, "x2": true, "trim": true, "outputDir": "/tmp/xxx" }`
25+
- export-selection:`{ "targetPath": "/a.psd", "targets": [{"psId":84,"name":"图标","exportName":"图标_84"}], "x1": true, "x2": false, "trim": true, "outputDir": "/tmp/xxx" }`
2426
- mutate-layers:`{ "targetPath": "/a.psd", "ops": [{"action":"hide","name":"组 5"}, {"action":"show","psId":84}, {"action":"delete","name":"组 7"}] }`(psId 优先精确定位;仅给 name 时匹配所有同名图层)
2527
- set-text:`{ "targetPath": "/a.psd", "edits": [{"psId":120,"text":"新文案"}, {"name":"标题","text":"Hello"}] }`
2628
- merge-groups:`{ "targetPath": "/a.psd", "targets": [{"psId":84}, {"name":"组 5"}] }`

0 commit comments

Comments
 (0)