@alisaitteke/photoshop-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +9 -0
- package/README.md +1300 -0
- package/dist/api/batch-play.d.ts +62 -0
- package/dist/api/batch-play.d.ts.map +1 -0
- package/dist/api/batch-play.js +131 -0
- package/dist/api/batch-play.js.map +1 -0
- package/dist/api/extendscript.d.ts +258 -0
- package/dist/api/extendscript.d.ts.map +1 -0
- package/dist/api/extendscript.js +1437 -0
- package/dist/api/extendscript.js.map +1 -0
- package/dist/api/photoshop-api.d.ts +20 -0
- package/dist/api/photoshop-api.d.ts.map +1 -0
- package/dist/api/photoshop-api.js +88 -0
- package/dist/api/photoshop-api.js.map +1 -0
- package/dist/core/server.d.ts +14 -0
- package/dist/core/server.d.ts.map +1 -0
- package/dist/core/server.js +191 -0
- package/dist/core/server.js.map +1 -0
- package/dist/core/session.d.ts +24 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +83 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/tool-registry.d.ts +23 -0
- package/dist/core/tool-registry.d.ts.map +1 -0
- package/dist/core/tool-registry.js +55 -0
- package/dist/core/tool-registry.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/platform/connection.d.ts +20 -0
- package/dist/platform/connection.d.ts.map +1 -0
- package/dist/platform/connection.js +94 -0
- package/dist/platform/connection.js.map +1 -0
- package/dist/platform/detector.d.ts +19 -0
- package/dist/platform/detector.d.ts.map +1 -0
- package/dist/platform/detector.js +63 -0
- package/dist/platform/detector.js.map +1 -0
- package/dist/platform/macos-detector.d.ts +13 -0
- package/dist/platform/macos-detector.d.ts.map +1 -0
- package/dist/platform/macos-detector.js +145 -0
- package/dist/platform/macos-detector.js.map +1 -0
- package/dist/platform/macos-executor.d.ts +22 -0
- package/dist/platform/macos-executor.d.ts.map +1 -0
- package/dist/platform/macos-executor.js +161 -0
- package/dist/platform/macos-executor.js.map +1 -0
- package/dist/platform/script-executor.d.ts +23 -0
- package/dist/platform/script-executor.d.ts.map +1 -0
- package/dist/platform/script-executor.js +2 -0
- package/dist/platform/script-executor.js.map +1 -0
- package/dist/platform/windows-detector.d.ts +14 -0
- package/dist/platform/windows-detector.d.ts.map +1 -0
- package/dist/platform/windows-detector.js +173 -0
- package/dist/platform/windows-detector.js.map +1 -0
- package/dist/platform/windows-executor.d.ts +15 -0
- package/dist/platform/windows-executor.d.ts.map +1 -0
- package/dist/platform/windows-executor.js +148 -0
- package/dist/platform/windows-executor.js.map +1 -0
- package/dist/tools/action-tools.d.ts +4 -0
- package/dist/tools/action-tools.d.ts.map +1 -0
- package/dist/tools/action-tools.js +102 -0
- package/dist/tools/action-tools.js.map +1 -0
- package/dist/tools/adjustment-tools.d.ts +4 -0
- package/dist/tools/adjustment-tools.d.ts.map +1 -0
- package/dist/tools/adjustment-tools.js +274 -0
- package/dist/tools/adjustment-tools.js.map +1 -0
- package/dist/tools/document-tools.d.ts +4 -0
- package/dist/tools/document-tools.d.ts.map +1 -0
- package/dist/tools/document-tools.js +230 -0
- package/dist/tools/document-tools.js.map +1 -0
- package/dist/tools/filter-tools.d.ts +4 -0
- package/dist/tools/filter-tools.d.ts.map +1 -0
- package/dist/tools/filter-tools.js +230 -0
- package/dist/tools/filter-tools.js.map +1 -0
- package/dist/tools/history-tools.d.ts +4 -0
- package/dist/tools/history-tools.d.ts.map +1 -0
- package/dist/tools/history-tools.js +137 -0
- package/dist/tools/history-tools.js.map +1 -0
- package/dist/tools/image-placement-tools.d.ts +4 -0
- package/dist/tools/image-placement-tools.d.ts.map +1 -0
- package/dist/tools/image-placement-tools.js +109 -0
- package/dist/tools/image-placement-tools.js.map +1 -0
- package/dist/tools/image-tools.d.ts +4 -0
- package/dist/tools/image-tools.d.ts.map +1 -0
- package/dist/tools/image-tools.js +123 -0
- package/dist/tools/image-tools.js.map +1 -0
- package/dist/tools/layer-ordering-tools.d.ts +4 -0
- package/dist/tools/layer-ordering-tools.d.ts.map +1 -0
- package/dist/tools/layer-ordering-tools.js +210 -0
- package/dist/tools/layer-ordering-tools.js.map +1 -0
- package/dist/tools/layer-properties-tools.d.ts +4 -0
- package/dist/tools/layer-properties-tools.d.ts.map +1 -0
- package/dist/tools/layer-properties-tools.js +421 -0
- package/dist/tools/layer-properties-tools.js.map +1 -0
- package/dist/tools/layer-tools.d.ts +4 -0
- package/dist/tools/layer-tools.d.ts.map +1 -0
- package/dist/tools/layer-tools.js +251 -0
- package/dist/tools/layer-tools.js.map +1 -0
- package/dist/tools/layer-transform-tools.d.ts +4 -0
- package/dist/tools/layer-transform-tools.d.ts.map +1 -0
- package/dist/tools/layer-transform-tools.js +199 -0
- package/dist/tools/layer-transform-tools.js.map +1 -0
- package/dist/tools/selection-tools.d.ts +4 -0
- package/dist/tools/selection-tools.d.ts.map +1 -0
- package/dist/tools/selection-tools.js +295 -0
- package/dist/tools/selection-tools.js.map +1 -0
- package/dist/tools/text-tools.d.ts +4 -0
- package/dist/tools/text-tools.d.ts.map +1 -0
- package/dist/tools/text-tools.js +210 -0
- package/dist/tools/text-tools.js.map +1 -0
- package/dist/utils/logger.d.ts +17 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +43 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,1437 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper functions for ExtendScript API
|
|
3
|
+
* ExtendScript is the legacy scripting API for Photoshop
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Helper functions for character/string ID conversion
|
|
7
|
+
*/
|
|
8
|
+
const helperFunctions = `
|
|
9
|
+
function cTID(s) { return app.charIDToTypeID(s); }
|
|
10
|
+
function sTID(s) { return app.stringIDToTypeID(s); }
|
|
11
|
+
`;
|
|
12
|
+
/**
|
|
13
|
+
* Helper function to get current context information
|
|
14
|
+
*/
|
|
15
|
+
const getContextInfo = `
|
|
16
|
+
function getContextInfo() {
|
|
17
|
+
var context = {
|
|
18
|
+
hasDocument: app.documents.length > 0
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
if (context.hasDocument) {
|
|
22
|
+
var doc = app.activeDocument;
|
|
23
|
+
context.document = {
|
|
24
|
+
name: doc.name,
|
|
25
|
+
width: doc.width.as('px'),
|
|
26
|
+
height: doc.height.as('px'),
|
|
27
|
+
resolution: doc.resolution,
|
|
28
|
+
colorMode: String(doc.mode),
|
|
29
|
+
layerCount: doc.layers.length,
|
|
30
|
+
hasSelection: doc.selection.bounds ? true : false
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if (doc.activeLayer) {
|
|
34
|
+
var layer = doc.activeLayer;
|
|
35
|
+
context.activeLayer = {
|
|
36
|
+
name: layer.name,
|
|
37
|
+
kind: String(layer.kind),
|
|
38
|
+
opacity: layer.opacity,
|
|
39
|
+
blendMode: String(layer.blendMode),
|
|
40
|
+
visible: layer.visible,
|
|
41
|
+
locked: layer.allLocked,
|
|
42
|
+
isBackground: layer.isBackgroundLayer
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Add bounds if available
|
|
46
|
+
try {
|
|
47
|
+
var bounds = layer.bounds;
|
|
48
|
+
context.activeLayer.bounds = {
|
|
49
|
+
left: bounds[0].as('px'),
|
|
50
|
+
top: bounds[1].as('px'),
|
|
51
|
+
right: bounds[2].as('px'),
|
|
52
|
+
bottom: bounds[3].as('px')
|
|
53
|
+
};
|
|
54
|
+
} catch (e) {
|
|
55
|
+
// Bounds not available for some layer types
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return context;
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
/**
|
|
64
|
+
* Common ExtendScript snippets
|
|
65
|
+
*/
|
|
66
|
+
export const ExtendScriptSnippets = {
|
|
67
|
+
/**
|
|
68
|
+
* Get Photoshop application info
|
|
69
|
+
*/
|
|
70
|
+
getAppInfo: () => `
|
|
71
|
+
return {
|
|
72
|
+
name: app.name,
|
|
73
|
+
version: app.version,
|
|
74
|
+
build: app.build
|
|
75
|
+
};
|
|
76
|
+
`,
|
|
77
|
+
/**
|
|
78
|
+
* Create a new document
|
|
79
|
+
*/
|
|
80
|
+
newDocument: (width, height, resolution = 72, colorMode = 'NewDocumentMode.RGB') => `
|
|
81
|
+
var doc = app.documents.add(
|
|
82
|
+
UnitValue(${width}, 'px'),
|
|
83
|
+
UnitValue(${height}, 'px'),
|
|
84
|
+
${resolution},
|
|
85
|
+
'New Document',
|
|
86
|
+
${colorMode}
|
|
87
|
+
);
|
|
88
|
+
return { id: doc.id, name: doc.name };
|
|
89
|
+
`,
|
|
90
|
+
/**
|
|
91
|
+
* Get active document info
|
|
92
|
+
*/
|
|
93
|
+
getDocumentInfo: () => `
|
|
94
|
+
${getContextInfo}
|
|
95
|
+
|
|
96
|
+
if (app.documents.length === 0) {
|
|
97
|
+
throw new Error('No active document');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
var context = getContextInfo();
|
|
101
|
+
return context;
|
|
102
|
+
`,
|
|
103
|
+
/**
|
|
104
|
+
* Create a text layer
|
|
105
|
+
*/
|
|
106
|
+
createTextLayer: (text, x = 100, y = 100, fontSize = 24) => `
|
|
107
|
+
${getContextInfo}
|
|
108
|
+
|
|
109
|
+
if (app.documents.length === 0) {
|
|
110
|
+
throw new Error('No active document');
|
|
111
|
+
}
|
|
112
|
+
var doc = app.activeDocument;
|
|
113
|
+
var textLayer = doc.artLayers.add();
|
|
114
|
+
textLayer.kind = LayerKind.TEXT;
|
|
115
|
+
textLayer.textItem.contents = "${text.replace(/"/g, '\\"')}";
|
|
116
|
+
textLayer.textItem.position = [${x}, ${y}];
|
|
117
|
+
textLayer.textItem.size = ${fontSize};
|
|
118
|
+
|
|
119
|
+
var result = {
|
|
120
|
+
created: true,
|
|
121
|
+
layerName: textLayer.name,
|
|
122
|
+
text: "${text.replace(/"/g, '\\"')}",
|
|
123
|
+
position: { x: ${x}, y: ${y} },
|
|
124
|
+
fontSize: ${fontSize},
|
|
125
|
+
context: getContextInfo()
|
|
126
|
+
};
|
|
127
|
+
return result;
|
|
128
|
+
`,
|
|
129
|
+
/**
|
|
130
|
+
* Place an image file as a layer
|
|
131
|
+
*/
|
|
132
|
+
placeImage: (filePath, x = 0, y = 0) => `
|
|
133
|
+
${helperFunctions}
|
|
134
|
+
${getContextInfo}
|
|
135
|
+
|
|
136
|
+
if (app.documents.length === 0) {
|
|
137
|
+
throw new Error('No active document');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
var imageFile = new File("${filePath.replace(/\\/g, '\\\\')}");
|
|
141
|
+
if (!imageFile.exists) {
|
|
142
|
+
throw new Error('Image file not found: ${filePath}');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Place image using ActionDescriptor
|
|
146
|
+
var desc = new ActionDescriptor();
|
|
147
|
+
desc.putPath(cTID('null'), imageFile);
|
|
148
|
+
desc.putEnumerated(cTID('FTcs'), cTID('QCSt'), cTID('Qcsa'));
|
|
149
|
+
|
|
150
|
+
var offsetDesc = new ActionDescriptor();
|
|
151
|
+
offsetDesc.putUnitDouble(cTID('Hrzn'), cTID('#Pxl'), ${x});
|
|
152
|
+
offsetDesc.putUnitDouble(cTID('Vrtc'), cTID('#Pxl'), ${y});
|
|
153
|
+
desc.putObject(cTID('Ofst'), cTID('Ofst'), offsetDesc);
|
|
154
|
+
|
|
155
|
+
executeAction(cTID('Plc '), desc, DialogModes.NO);
|
|
156
|
+
|
|
157
|
+
var layer = app.activeDocument.activeLayer;
|
|
158
|
+
var result = {
|
|
159
|
+
placed: true,
|
|
160
|
+
layerName: layer.name,
|
|
161
|
+
filePath: "${filePath}",
|
|
162
|
+
position: { x: ${x}, y: ${y} },
|
|
163
|
+
layerBounds: {
|
|
164
|
+
width: layer.bounds[2].as('px') - layer.bounds[0].as('px'),
|
|
165
|
+
height: layer.bounds[3].as('px') - layer.bounds[1].as('px')
|
|
166
|
+
},
|
|
167
|
+
context: getContextInfo()
|
|
168
|
+
};
|
|
169
|
+
return result;
|
|
170
|
+
`,
|
|
171
|
+
/**
|
|
172
|
+
* Open an image file as a new document
|
|
173
|
+
*/
|
|
174
|
+
openImage: (filePath) => `
|
|
175
|
+
var imageFile = new File("${filePath.replace(/\\/g, '\\\\')}");
|
|
176
|
+
if (!imageFile.exists) {
|
|
177
|
+
throw new Error('Image file not found: ${filePath}');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
var doc = app.open(imageFile);
|
|
181
|
+
return {
|
|
182
|
+
id: doc.id,
|
|
183
|
+
name: doc.name,
|
|
184
|
+
width: doc.width.as('px'),
|
|
185
|
+
height: doc.height.as('px')
|
|
186
|
+
};
|
|
187
|
+
`,
|
|
188
|
+
/**
|
|
189
|
+
* Save document as PSD
|
|
190
|
+
*/
|
|
191
|
+
saveAsPSD: (path) => `
|
|
192
|
+
if (app.documents.length === 0) {
|
|
193
|
+
throw new Error('No active document');
|
|
194
|
+
}
|
|
195
|
+
var doc = app.activeDocument;
|
|
196
|
+
var saveFile = new File("${path.replace(/\\/g, '\\\\')}");
|
|
197
|
+
var psdOptions = new PhotoshopSaveOptions();
|
|
198
|
+
psdOptions.embedColorProfile = true;
|
|
199
|
+
doc.saveAs(saveFile, psdOptions, true);
|
|
200
|
+
return { path: saveFile.fsName };
|
|
201
|
+
`,
|
|
202
|
+
/**
|
|
203
|
+
* Save document as JPEG
|
|
204
|
+
*/
|
|
205
|
+
saveAsJPEG: (path, quality = 8) => `
|
|
206
|
+
if (app.documents.length === 0) {
|
|
207
|
+
throw new Error('No active document');
|
|
208
|
+
}
|
|
209
|
+
var doc = app.activeDocument;
|
|
210
|
+
var saveFile = new File("${path.replace(/\\/g, '\\\\')}");
|
|
211
|
+
var jpegOptions = new JPEGSaveOptions();
|
|
212
|
+
jpegOptions.quality = ${quality};
|
|
213
|
+
jpegOptions.embedColorProfile = true;
|
|
214
|
+
doc.saveAs(saveFile, jpegOptions, true);
|
|
215
|
+
return { path: saveFile.fsName };
|
|
216
|
+
`,
|
|
217
|
+
/**
|
|
218
|
+
* Save document as PNG
|
|
219
|
+
*/
|
|
220
|
+
saveAsPNG: (path) => `
|
|
221
|
+
if (app.documents.length === 0) {
|
|
222
|
+
throw new Error('No active document');
|
|
223
|
+
}
|
|
224
|
+
var doc = app.activeDocument;
|
|
225
|
+
var saveFile = new File("${path.replace(/\\/g, '\\\\')}");
|
|
226
|
+
var pngOptions = new PNGSaveOptions();
|
|
227
|
+
pngOptions.compression = 9;
|
|
228
|
+
doc.saveAs(saveFile, pngOptions, true);
|
|
229
|
+
return { path: saveFile.fsName };
|
|
230
|
+
`,
|
|
231
|
+
/**
|
|
232
|
+
* Close active document
|
|
233
|
+
*/
|
|
234
|
+
closeDocument: (save = false) => `
|
|
235
|
+
if (app.documents.length === 0) {
|
|
236
|
+
throw new Error('No active document');
|
|
237
|
+
}
|
|
238
|
+
var doc = app.activeDocument;
|
|
239
|
+
doc.close(${save ? 'SaveOptions.SAVECHANGES' : 'SaveOptions.DONOTSAVECHANGES'});
|
|
240
|
+
return { closed: true };
|
|
241
|
+
`,
|
|
242
|
+
/**
|
|
243
|
+
* Create a new layer
|
|
244
|
+
*/
|
|
245
|
+
newLayer: (name) => `
|
|
246
|
+
${getContextInfo}
|
|
247
|
+
|
|
248
|
+
if (app.documents.length === 0) {
|
|
249
|
+
throw new Error('No active document');
|
|
250
|
+
}
|
|
251
|
+
var doc = app.activeDocument;
|
|
252
|
+
var layer = doc.artLayers.add();
|
|
253
|
+
${name ? `layer.name = "${name.replace(/"/g, '\\"')}";` : ''}
|
|
254
|
+
|
|
255
|
+
var result = {
|
|
256
|
+
created: true,
|
|
257
|
+
layerName: layer.name,
|
|
258
|
+
context: getContextInfo()
|
|
259
|
+
};
|
|
260
|
+
return result;
|
|
261
|
+
`,
|
|
262
|
+
/**
|
|
263
|
+
* Delete active layer
|
|
264
|
+
*/
|
|
265
|
+
deleteLayer: () => `
|
|
266
|
+
if (app.documents.length === 0) {
|
|
267
|
+
throw new Error('No active document');
|
|
268
|
+
}
|
|
269
|
+
var doc = app.activeDocument;
|
|
270
|
+
if (doc.activeLayer) {
|
|
271
|
+
doc.activeLayer.remove();
|
|
272
|
+
return { deleted: true };
|
|
273
|
+
}
|
|
274
|
+
throw new Error('No active layer');
|
|
275
|
+
`,
|
|
276
|
+
/**
|
|
277
|
+
* Fill layer with color
|
|
278
|
+
*/
|
|
279
|
+
fillLayer: (red, green, blue) => `
|
|
280
|
+
if (app.documents.length === 0) {
|
|
281
|
+
throw new Error('No active document');
|
|
282
|
+
}
|
|
283
|
+
var doc = app.activeDocument;
|
|
284
|
+
var color = new SolidColor();
|
|
285
|
+
color.rgb.red = ${red};
|
|
286
|
+
color.rgb.green = ${green};
|
|
287
|
+
color.rgb.blue = ${blue};
|
|
288
|
+
doc.activeLayer.fillPath(color);
|
|
289
|
+
return { filled: true };
|
|
290
|
+
`,
|
|
291
|
+
/**
|
|
292
|
+
* Resize image
|
|
293
|
+
*/
|
|
294
|
+
resizeImage: (width, height) => `
|
|
295
|
+
if (app.documents.length === 0) {
|
|
296
|
+
throw new Error('No active document');
|
|
297
|
+
}
|
|
298
|
+
var doc = app.activeDocument;
|
|
299
|
+
doc.resizeImage(
|
|
300
|
+
UnitValue(${width}, 'px'),
|
|
301
|
+
UnitValue(${height}, 'px'),
|
|
302
|
+
null,
|
|
303
|
+
ResampleMethod.BICUBIC
|
|
304
|
+
);
|
|
305
|
+
return {
|
|
306
|
+
width: doc.width.as('px'),
|
|
307
|
+
height: doc.height.as('px')
|
|
308
|
+
};
|
|
309
|
+
`,
|
|
310
|
+
/**
|
|
311
|
+
* Get all layer names
|
|
312
|
+
*/
|
|
313
|
+
getLayerNames: () => `
|
|
314
|
+
${getContextInfo}
|
|
315
|
+
|
|
316
|
+
if (app.documents.length === 0) {
|
|
317
|
+
throw new Error('No active document');
|
|
318
|
+
}
|
|
319
|
+
var doc = app.activeDocument;
|
|
320
|
+
var layers = [];
|
|
321
|
+
for (var i = 0; i < doc.layers.length; i++) {
|
|
322
|
+
var layer = doc.layers[i];
|
|
323
|
+
layers.push({
|
|
324
|
+
name: layer.name,
|
|
325
|
+
kind: String(layer.kind),
|
|
326
|
+
visible: layer.visible,
|
|
327
|
+
opacity: layer.opacity,
|
|
328
|
+
blendMode: String(layer.blendMode)
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
var result = {
|
|
333
|
+
layerCount: layers.length,
|
|
334
|
+
layers: layers,
|
|
335
|
+
context: getContextInfo()
|
|
336
|
+
};
|
|
337
|
+
return result;
|
|
338
|
+
`,
|
|
339
|
+
/**
|
|
340
|
+
* Select layer by name
|
|
341
|
+
*/
|
|
342
|
+
selectLayer: (name) => `
|
|
343
|
+
if (app.documents.length === 0) {
|
|
344
|
+
throw new Error('No active document');
|
|
345
|
+
}
|
|
346
|
+
var doc = app.activeDocument;
|
|
347
|
+
for (var i = 0; i < doc.layers.length; i++) {
|
|
348
|
+
if (doc.layers[i].name === "${name.replace(/"/g, '\\"')}") {
|
|
349
|
+
doc.activeLayer = doc.layers[i];
|
|
350
|
+
return { selected: true, name: doc.layers[i].name };
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
throw new Error('Layer not found: ${name.replace(/"/g, '\\"')}');
|
|
354
|
+
`,
|
|
355
|
+
/**
|
|
356
|
+
* Scale active layer to fit document (maintain aspect ratio)
|
|
357
|
+
*/
|
|
358
|
+
fitLayerToDocument: (fillDocument = false) => `
|
|
359
|
+
${getContextInfo}
|
|
360
|
+
|
|
361
|
+
if (app.documents.length === 0) {
|
|
362
|
+
throw new Error('No active document');
|
|
363
|
+
}
|
|
364
|
+
var doc = app.activeDocument;
|
|
365
|
+
var layer = doc.activeLayer;
|
|
366
|
+
|
|
367
|
+
if (layer.isBackgroundLayer) {
|
|
368
|
+
throw new Error('Cannot transform background layer');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Get canvas dimensions
|
|
372
|
+
var canvasWidth = doc.width.as('px');
|
|
373
|
+
var canvasHeight = doc.height.as('px');
|
|
374
|
+
|
|
375
|
+
// Get layer bounds
|
|
376
|
+
var bounds = layer.bounds;
|
|
377
|
+
var layerWidth = bounds[2].as('px') - bounds[0].as('px');
|
|
378
|
+
var layerHeight = bounds[3].as('px') - bounds[1].as('px');
|
|
379
|
+
|
|
380
|
+
// Calculate scale ratios
|
|
381
|
+
var widthRatio = canvasWidth / layerWidth;
|
|
382
|
+
var heightRatio = canvasHeight / layerHeight;
|
|
383
|
+
|
|
384
|
+
// Choose scale factor based on fill or fit mode
|
|
385
|
+
var scaleFactor;
|
|
386
|
+
if (${fillDocument}) {
|
|
387
|
+
// Fill: scale to cover entire canvas (may crop)
|
|
388
|
+
scaleFactor = Math.max(widthRatio, heightRatio);
|
|
389
|
+
} else {
|
|
390
|
+
// Fit: scale to fit within canvas (may have margins)
|
|
391
|
+
scaleFactor = Math.min(widthRatio, heightRatio);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Apply scale
|
|
395
|
+
var scalePercent = scaleFactor * 100;
|
|
396
|
+
layer.resize(scalePercent, scalePercent, AnchorPosition.MIDDLECENTER);
|
|
397
|
+
|
|
398
|
+
// Center the layer
|
|
399
|
+
layer.translate(
|
|
400
|
+
canvasWidth / 2 - (bounds[0].as('px') + layerWidth / 2),
|
|
401
|
+
canvasHeight / 2 - (bounds[1].as('px') + layerHeight / 2)
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
var result = {
|
|
405
|
+
fitted: true,
|
|
406
|
+
mode: ${fillDocument} ? 'fill' : 'fit',
|
|
407
|
+
originalSize: { width: layerWidth, height: layerHeight },
|
|
408
|
+
newSize: {
|
|
409
|
+
width: layerWidth * scaleFactor,
|
|
410
|
+
height: layerHeight * scaleFactor
|
|
411
|
+
},
|
|
412
|
+
scaleFactor: scaleFactor,
|
|
413
|
+
scalePercent: scalePercent,
|
|
414
|
+
context: getContextInfo()
|
|
415
|
+
};
|
|
416
|
+
return result;
|
|
417
|
+
`,
|
|
418
|
+
/**
|
|
419
|
+
* Scale active layer by percentage
|
|
420
|
+
*/
|
|
421
|
+
scaleLayer: (scalePercent, centerAnchor = true) => `
|
|
422
|
+
if (app.documents.length === 0) {
|
|
423
|
+
throw new Error('No active document');
|
|
424
|
+
}
|
|
425
|
+
var doc = app.activeDocument;
|
|
426
|
+
var layer = doc.activeLayer;
|
|
427
|
+
|
|
428
|
+
if (layer.isBackgroundLayer) {
|
|
429
|
+
throw new Error('Cannot transform background layer');
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
var anchor = ${centerAnchor ? 'AnchorPosition.MIDDLECENTER' : 'AnchorPosition.TOPLEFT'};
|
|
433
|
+
layer.resize(${scalePercent}, ${scalePercent}, anchor);
|
|
434
|
+
|
|
435
|
+
return {
|
|
436
|
+
scaled: true,
|
|
437
|
+
percent: ${scalePercent}
|
|
438
|
+
};
|
|
439
|
+
`,
|
|
440
|
+
/**
|
|
441
|
+
* Move/translate active layer
|
|
442
|
+
*/
|
|
443
|
+
moveLayer: (deltaX, deltaY) => `
|
|
444
|
+
if (app.documents.length === 0) {
|
|
445
|
+
throw new Error('No active document');
|
|
446
|
+
}
|
|
447
|
+
var doc = app.activeDocument;
|
|
448
|
+
var layer = doc.activeLayer;
|
|
449
|
+
|
|
450
|
+
if (layer.isBackgroundLayer) {
|
|
451
|
+
throw new Error('Cannot move background layer');
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
layer.translate(${deltaX}, ${deltaY});
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
moved: true,
|
|
458
|
+
deltaX: ${deltaX},
|
|
459
|
+
deltaY: ${deltaY}
|
|
460
|
+
};
|
|
461
|
+
`,
|
|
462
|
+
/**
|
|
463
|
+
* Rotate active layer
|
|
464
|
+
*/
|
|
465
|
+
rotateLayer: (degrees) => `
|
|
466
|
+
if (app.documents.length === 0) {
|
|
467
|
+
throw new Error('No active document');
|
|
468
|
+
}
|
|
469
|
+
var doc = app.activeDocument;
|
|
470
|
+
var layer = doc.activeLayer;
|
|
471
|
+
|
|
472
|
+
if (layer.isBackgroundLayer) {
|
|
473
|
+
throw new Error('Cannot rotate background layer');
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
layer.rotate(${degrees}, AnchorPosition.MIDDLECENTER);
|
|
477
|
+
|
|
478
|
+
return {
|
|
479
|
+
rotated: true,
|
|
480
|
+
degrees: ${degrees}
|
|
481
|
+
};
|
|
482
|
+
`,
|
|
483
|
+
/**
|
|
484
|
+
* Set layer opacity
|
|
485
|
+
*/
|
|
486
|
+
setLayerOpacity: (opacity) => `
|
|
487
|
+
${getContextInfo}
|
|
488
|
+
|
|
489
|
+
if (app.documents.length === 0) {
|
|
490
|
+
throw new Error('No active document');
|
|
491
|
+
}
|
|
492
|
+
var doc = app.activeDocument;
|
|
493
|
+
var layer = doc.activeLayer;
|
|
494
|
+
|
|
495
|
+
layer.opacity = ${opacity};
|
|
496
|
+
|
|
497
|
+
var result = {
|
|
498
|
+
updated: true,
|
|
499
|
+
property: 'opacity',
|
|
500
|
+
value: layer.opacity,
|
|
501
|
+
layerName: layer.name,
|
|
502
|
+
context: getContextInfo()
|
|
503
|
+
};
|
|
504
|
+
return result;
|
|
505
|
+
`,
|
|
506
|
+
/**
|
|
507
|
+
* Set layer blend mode
|
|
508
|
+
*/
|
|
509
|
+
setLayerBlendMode: (blendMode) => `
|
|
510
|
+
${getContextInfo}
|
|
511
|
+
|
|
512
|
+
if (app.documents.length === 0) {
|
|
513
|
+
throw new Error('No active document');
|
|
514
|
+
}
|
|
515
|
+
var doc = app.activeDocument;
|
|
516
|
+
var layer = doc.activeLayer;
|
|
517
|
+
|
|
518
|
+
layer.blendMode = BlendMode.${blendMode};
|
|
519
|
+
|
|
520
|
+
var result = {
|
|
521
|
+
updated: true,
|
|
522
|
+
property: 'blendMode',
|
|
523
|
+
value: String(layer.blendMode),
|
|
524
|
+
layerName: layer.name,
|
|
525
|
+
context: getContextInfo()
|
|
526
|
+
};
|
|
527
|
+
return result;
|
|
528
|
+
`,
|
|
529
|
+
/**
|
|
530
|
+
* Set layer visibility
|
|
531
|
+
*/
|
|
532
|
+
setLayerVisibility: (visible) => `
|
|
533
|
+
if (app.documents.length === 0) {
|
|
534
|
+
throw new Error('No active document');
|
|
535
|
+
}
|
|
536
|
+
var doc = app.activeDocument;
|
|
537
|
+
var layer = doc.activeLayer;
|
|
538
|
+
|
|
539
|
+
layer.visible = ${visible};
|
|
540
|
+
|
|
541
|
+
return {
|
|
542
|
+
visible: layer.visible,
|
|
543
|
+
name: layer.name
|
|
544
|
+
};
|
|
545
|
+
`,
|
|
546
|
+
/**
|
|
547
|
+
* Lock/unlock layer
|
|
548
|
+
*/
|
|
549
|
+
setLayerLocked: (locked) => `
|
|
550
|
+
if (app.documents.length === 0) {
|
|
551
|
+
throw new Error('No active document');
|
|
552
|
+
}
|
|
553
|
+
var doc = app.activeDocument;
|
|
554
|
+
var layer = doc.activeLayer;
|
|
555
|
+
|
|
556
|
+
layer.allLocked = ${locked};
|
|
557
|
+
|
|
558
|
+
return {
|
|
559
|
+
locked: layer.allLocked,
|
|
560
|
+
name: layer.name
|
|
561
|
+
};
|
|
562
|
+
`,
|
|
563
|
+
/**
|
|
564
|
+
* Rename active layer
|
|
565
|
+
*/
|
|
566
|
+
renameLayer: (newName) => `
|
|
567
|
+
if (app.documents.length === 0) {
|
|
568
|
+
throw new Error('No active document');
|
|
569
|
+
}
|
|
570
|
+
var doc = app.activeDocument;
|
|
571
|
+
var layer = doc.activeLayer;
|
|
572
|
+
|
|
573
|
+
var oldName = layer.name;
|
|
574
|
+
layer.name = "${newName.replace(/"/g, '\\"')}";
|
|
575
|
+
|
|
576
|
+
return {
|
|
577
|
+
oldName: oldName,
|
|
578
|
+
newName: layer.name
|
|
579
|
+
};
|
|
580
|
+
`,
|
|
581
|
+
/**
|
|
582
|
+
* Duplicate active layer
|
|
583
|
+
*/
|
|
584
|
+
duplicateLayer: (newName) => `
|
|
585
|
+
if (app.documents.length === 0) {
|
|
586
|
+
throw new Error('No active document');
|
|
587
|
+
}
|
|
588
|
+
var doc = app.activeDocument;
|
|
589
|
+
var layer = doc.activeLayer;
|
|
590
|
+
|
|
591
|
+
var duplicated = layer.duplicate();
|
|
592
|
+
${newName ? `duplicated.name = "${newName.replace(/"/g, '\\"')}";` : ''}
|
|
593
|
+
|
|
594
|
+
return {
|
|
595
|
+
originalName: layer.name,
|
|
596
|
+
newName: duplicated.name
|
|
597
|
+
};
|
|
598
|
+
`,
|
|
599
|
+
/**
|
|
600
|
+
* Merge visible layers
|
|
601
|
+
*/
|
|
602
|
+
mergeVisibleLayers: () => `
|
|
603
|
+
if (app.documents.length === 0) {
|
|
604
|
+
throw new Error('No active document');
|
|
605
|
+
}
|
|
606
|
+
var doc = app.activeDocument;
|
|
607
|
+
doc.mergeVisibleLayers();
|
|
608
|
+
|
|
609
|
+
return {
|
|
610
|
+
merged: true
|
|
611
|
+
};
|
|
612
|
+
`,
|
|
613
|
+
/**
|
|
614
|
+
* Flatten image (merge all layers)
|
|
615
|
+
*/
|
|
616
|
+
flattenImage: () => `
|
|
617
|
+
if (app.documents.length === 0) {
|
|
618
|
+
throw new Error('No active document');
|
|
619
|
+
}
|
|
620
|
+
var doc = app.activeDocument;
|
|
621
|
+
doc.flatten();
|
|
622
|
+
|
|
623
|
+
return {
|
|
624
|
+
flattened: true
|
|
625
|
+
};
|
|
626
|
+
`,
|
|
627
|
+
/**
|
|
628
|
+
* Apply Gaussian Blur filter
|
|
629
|
+
*/
|
|
630
|
+
applyGaussianBlur: (radius) => `
|
|
631
|
+
${getContextInfo}
|
|
632
|
+
|
|
633
|
+
if (app.documents.length === 0) {
|
|
634
|
+
throw new Error('No active document');
|
|
635
|
+
}
|
|
636
|
+
var layer = app.activeDocument.activeLayer;
|
|
637
|
+
var wasRasterized = false;
|
|
638
|
+
|
|
639
|
+
// Auto-rasterize if needed
|
|
640
|
+
if (layer.kind === LayerKind.TEXT || layer.kind === LayerKind.SMARTOBJECT) {
|
|
641
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
642
|
+
wasRasterized = true;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
if (layer.kind !== LayerKind.NORMAL) {
|
|
646
|
+
throw new Error('Can only apply filters to normal (raster) layers. Layer kind: ' + layer.kind);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
layer.applyGaussianBlur(${radius});
|
|
650
|
+
|
|
651
|
+
var result = {
|
|
652
|
+
applied: true,
|
|
653
|
+
filter: 'Gaussian Blur',
|
|
654
|
+
radius: ${radius},
|
|
655
|
+
wasRasterized: wasRasterized,
|
|
656
|
+
context: getContextInfo()
|
|
657
|
+
};
|
|
658
|
+
return result;
|
|
659
|
+
`,
|
|
660
|
+
/**
|
|
661
|
+
* Apply Unsharp Mask (sharpen)
|
|
662
|
+
*/
|
|
663
|
+
applyUnsharpMask: (amount, radius, threshold) => `
|
|
664
|
+
if (app.documents.length === 0) {
|
|
665
|
+
throw new Error('No active document');
|
|
666
|
+
}
|
|
667
|
+
var layer = app.activeDocument.activeLayer;
|
|
668
|
+
|
|
669
|
+
// Auto-rasterize if needed
|
|
670
|
+
if (layer.kind === LayerKind.TEXT || layer.kind === LayerKind.SMARTOBJECT) {
|
|
671
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
if (layer.kind !== LayerKind.NORMAL) {
|
|
675
|
+
throw new Error('Can only apply filters to normal (raster) layers');
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
layer.applyUnSharpMask(${amount}, ${radius}, ${threshold});
|
|
679
|
+
|
|
680
|
+
return {
|
|
681
|
+
filter: 'Unsharp Mask',
|
|
682
|
+
amount: ${amount},
|
|
683
|
+
radius: ${radius},
|
|
684
|
+
threshold: ${threshold}
|
|
685
|
+
};
|
|
686
|
+
`,
|
|
687
|
+
/**
|
|
688
|
+
* Apply Add Noise filter
|
|
689
|
+
*/
|
|
690
|
+
applyAddNoise: (amount, distribution, monochromatic) => `
|
|
691
|
+
if (app.documents.length === 0) {
|
|
692
|
+
throw new Error('No active document');
|
|
693
|
+
}
|
|
694
|
+
var layer = app.activeDocument.activeLayer;
|
|
695
|
+
|
|
696
|
+
// Auto-rasterize if needed
|
|
697
|
+
if (layer.kind === LayerKind.TEXT || layer.kind === LayerKind.SMARTOBJECT) {
|
|
698
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if (layer.kind !== LayerKind.NORMAL) {
|
|
702
|
+
throw new Error('Can only apply filters to normal (raster) layers');
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
var distEnum = NoiseDistribution.${distribution};
|
|
706
|
+
layer.applyAddNoise(${amount}, distEnum, ${monochromatic});
|
|
707
|
+
|
|
708
|
+
return {
|
|
709
|
+
filter: 'Add Noise',
|
|
710
|
+
amount: ${amount},
|
|
711
|
+
distribution: '${distribution}',
|
|
712
|
+
monochromatic: ${monochromatic}
|
|
713
|
+
};
|
|
714
|
+
`,
|
|
715
|
+
/**
|
|
716
|
+
* Apply Motion Blur filter
|
|
717
|
+
*/
|
|
718
|
+
applyMotionBlur: (angle, radius) => `
|
|
719
|
+
if (app.documents.length === 0) {
|
|
720
|
+
throw new Error('No active document');
|
|
721
|
+
}
|
|
722
|
+
var layer = app.activeDocument.activeLayer;
|
|
723
|
+
|
|
724
|
+
// Auto-rasterize if needed
|
|
725
|
+
if (layer.kind === LayerKind.TEXT || layer.kind === LayerKind.SMARTOBJECT) {
|
|
726
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
if (layer.kind !== LayerKind.NORMAL) {
|
|
730
|
+
throw new Error('Can only apply filters to normal (raster) layers');
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
layer.applyMotionBlur(${angle}, ${radius});
|
|
734
|
+
|
|
735
|
+
return {
|
|
736
|
+
filter: 'Motion Blur',
|
|
737
|
+
angle: ${angle},
|
|
738
|
+
radius: ${radius}
|
|
739
|
+
};
|
|
740
|
+
`,
|
|
741
|
+
/**
|
|
742
|
+
* Adjust brightness and contrast
|
|
743
|
+
*/
|
|
744
|
+
adjustBrightnessContrast: (brightness, contrast) => `
|
|
745
|
+
if (app.documents.length === 0) {
|
|
746
|
+
throw new Error('No active document');
|
|
747
|
+
}
|
|
748
|
+
var layer = app.activeDocument.activeLayer;
|
|
749
|
+
|
|
750
|
+
// Auto-rasterize if needed
|
|
751
|
+
if (layer.kind === LayerKind.TEXT || layer.kind === LayerKind.SMARTOBJECT) {
|
|
752
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
layer.adjustBrightnessContrast(${brightness}, ${contrast});
|
|
756
|
+
|
|
757
|
+
return {
|
|
758
|
+
adjustment: 'Brightness/Contrast',
|
|
759
|
+
brightness: ${brightness},
|
|
760
|
+
contrast: ${contrast}
|
|
761
|
+
};
|
|
762
|
+
`,
|
|
763
|
+
/**
|
|
764
|
+
* Adjust hue and saturation
|
|
765
|
+
*/
|
|
766
|
+
adjustHueSaturation: (hue, saturation, lightness) => `
|
|
767
|
+
if (app.documents.length === 0) {
|
|
768
|
+
throw new Error('No active document');
|
|
769
|
+
}
|
|
770
|
+
var layer = app.activeDocument.activeLayer;
|
|
771
|
+
|
|
772
|
+
layer.adjustColorBalance([${hue}], [${saturation}], [${lightness}]);
|
|
773
|
+
|
|
774
|
+
return {
|
|
775
|
+
adjustment: 'Hue/Saturation',
|
|
776
|
+
hue: ${hue},
|
|
777
|
+
saturation: ${saturation},
|
|
778
|
+
lightness: ${lightness}
|
|
779
|
+
};
|
|
780
|
+
`,
|
|
781
|
+
/**
|
|
782
|
+
* Auto levels adjustment
|
|
783
|
+
*/
|
|
784
|
+
autoLevels: () => `
|
|
785
|
+
if (app.documents.length === 0) {
|
|
786
|
+
throw new Error('No active document');
|
|
787
|
+
}
|
|
788
|
+
var layer = app.activeDocument.activeLayer;
|
|
789
|
+
|
|
790
|
+
// Auto-rasterize if needed
|
|
791
|
+
if (layer.kind === LayerKind.TEXT || layer.kind === LayerKind.SMARTOBJECT) {
|
|
792
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
layer.autoLevels();
|
|
796
|
+
|
|
797
|
+
return {
|
|
798
|
+
adjustment: 'Auto Levels'
|
|
799
|
+
};
|
|
800
|
+
`,
|
|
801
|
+
/**
|
|
802
|
+
* Auto contrast adjustment
|
|
803
|
+
*/
|
|
804
|
+
autoContrast: () => `
|
|
805
|
+
if (app.documents.length === 0) {
|
|
806
|
+
throw new Error('No active document');
|
|
807
|
+
}
|
|
808
|
+
var layer = app.activeDocument.activeLayer;
|
|
809
|
+
|
|
810
|
+
// Auto-rasterize if needed
|
|
811
|
+
if (layer.kind === LayerKind.TEXT || layer.kind === LayerKind.SMARTOBJECT) {
|
|
812
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
layer.autoContrast();
|
|
816
|
+
|
|
817
|
+
return {
|
|
818
|
+
adjustment: 'Auto Contrast'
|
|
819
|
+
};
|
|
820
|
+
`,
|
|
821
|
+
/**
|
|
822
|
+
* Desaturate (convert to grayscale without changing color mode)
|
|
823
|
+
*/
|
|
824
|
+
desaturate: () => `
|
|
825
|
+
if (app.documents.length === 0) {
|
|
826
|
+
throw new Error('No active document');
|
|
827
|
+
}
|
|
828
|
+
var layer = app.activeDocument.activeLayer;
|
|
829
|
+
|
|
830
|
+
// Auto-rasterize if needed
|
|
831
|
+
if (layer.kind === LayerKind.TEXT || layer.kind === LayerKind.SMARTOBJECT) {
|
|
832
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
layer.desaturate();
|
|
836
|
+
|
|
837
|
+
return {
|
|
838
|
+
adjustment: 'Desaturate'
|
|
839
|
+
};
|
|
840
|
+
`,
|
|
841
|
+
/**
|
|
842
|
+
* Invert colors
|
|
843
|
+
*/
|
|
844
|
+
invert: () => `
|
|
845
|
+
if (app.documents.length === 0) {
|
|
846
|
+
throw new Error('No active document');
|
|
847
|
+
}
|
|
848
|
+
var layer = app.activeDocument.activeLayer;
|
|
849
|
+
|
|
850
|
+
// Auto-rasterize if needed
|
|
851
|
+
if (layer.kind === LayerKind.TEXT || layer.kind === LayerKind.SMARTOBJECT) {
|
|
852
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
layer.invert();
|
|
856
|
+
|
|
857
|
+
return {
|
|
858
|
+
adjustment: 'Invert'
|
|
859
|
+
};
|
|
860
|
+
`,
|
|
861
|
+
/**
|
|
862
|
+
* Crop document
|
|
863
|
+
*/
|
|
864
|
+
cropDocument: (left, top, right, bottom) => `
|
|
865
|
+
if (app.documents.length === 0) {
|
|
866
|
+
throw new Error('No active document');
|
|
867
|
+
}
|
|
868
|
+
var doc = app.activeDocument;
|
|
869
|
+
|
|
870
|
+
var bounds = [${left}, ${top}, ${right}, ${bottom}];
|
|
871
|
+
doc.crop(bounds);
|
|
872
|
+
|
|
873
|
+
return {
|
|
874
|
+
cropped: true,
|
|
875
|
+
newWidth: doc.width.as('px'),
|
|
876
|
+
newHeight: doc.height.as('px')
|
|
877
|
+
};
|
|
878
|
+
`,
|
|
879
|
+
/**
|
|
880
|
+
* Set text layer font
|
|
881
|
+
*/
|
|
882
|
+
setTextFont: (fontName, fontSize) => `
|
|
883
|
+
if (app.documents.length === 0) {
|
|
884
|
+
throw new Error('No active document');
|
|
885
|
+
}
|
|
886
|
+
var layer = app.activeDocument.activeLayer;
|
|
887
|
+
|
|
888
|
+
if (layer.kind !== LayerKind.TEXT) {
|
|
889
|
+
throw new Error('Active layer is not a text layer');
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
layer.textItem.font = "${fontName.replace(/"/g, '\\"')}";
|
|
893
|
+
${fontSize ? `layer.textItem.size = ${fontSize};` : ''}
|
|
894
|
+
|
|
895
|
+
return {
|
|
896
|
+
font: layer.textItem.font,
|
|
897
|
+
size: layer.textItem.size
|
|
898
|
+
};
|
|
899
|
+
`,
|
|
900
|
+
/**
|
|
901
|
+
* Set text color
|
|
902
|
+
*/
|
|
903
|
+
setTextColor: (red, green, blue) => `
|
|
904
|
+
if (app.documents.length === 0) {
|
|
905
|
+
throw new Error('No active document');
|
|
906
|
+
}
|
|
907
|
+
var layer = app.activeDocument.activeLayer;
|
|
908
|
+
|
|
909
|
+
if (layer.kind !== LayerKind.TEXT) {
|
|
910
|
+
throw new Error('Active layer is not a text layer');
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
var color = new SolidColor();
|
|
914
|
+
color.rgb.red = ${red};
|
|
915
|
+
color.rgb.green = ${green};
|
|
916
|
+
color.rgb.blue = ${blue};
|
|
917
|
+
layer.textItem.color = color;
|
|
918
|
+
|
|
919
|
+
return {
|
|
920
|
+
color: 'RGB(' + ${red} + ', ' + ${green} + ', ' + ${blue} + ')'
|
|
921
|
+
};
|
|
922
|
+
`,
|
|
923
|
+
/**
|
|
924
|
+
* Set text alignment
|
|
925
|
+
*/
|
|
926
|
+
setTextAlignment: (alignment) => `
|
|
927
|
+
if (app.documents.length === 0) {
|
|
928
|
+
throw new Error('No active document');
|
|
929
|
+
}
|
|
930
|
+
var layer = app.activeDocument.activeLayer;
|
|
931
|
+
|
|
932
|
+
if (layer.kind !== LayerKind.TEXT) {
|
|
933
|
+
throw new Error('Active layer is not a text layer');
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
layer.textItem.justification = Justification.${alignment};
|
|
937
|
+
|
|
938
|
+
return {
|
|
939
|
+
alignment: '${alignment}'
|
|
940
|
+
};
|
|
941
|
+
`,
|
|
942
|
+
/**
|
|
943
|
+
* Update text content
|
|
944
|
+
*/
|
|
945
|
+
updateTextContent: (newText) => `
|
|
946
|
+
if (app.documents.length === 0) {
|
|
947
|
+
throw new Error('No active document');
|
|
948
|
+
}
|
|
949
|
+
var layer = app.activeDocument.activeLayer;
|
|
950
|
+
|
|
951
|
+
if (layer.kind !== LayerKind.TEXT) {
|
|
952
|
+
throw new Error('Active layer is not a text layer');
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
layer.textItem.contents = "${newText.replace(/"/g, '\\"')}";
|
|
956
|
+
|
|
957
|
+
return {
|
|
958
|
+
text: layer.textItem.contents
|
|
959
|
+
};
|
|
960
|
+
`,
|
|
961
|
+
/**
|
|
962
|
+
* Create rectangular selection
|
|
963
|
+
*/
|
|
964
|
+
selectRectangle: (left, top, right, bottom) => `
|
|
965
|
+
if (app.documents.length === 0) {
|
|
966
|
+
throw new Error('No active document');
|
|
967
|
+
}
|
|
968
|
+
var doc = app.activeDocument;
|
|
969
|
+
|
|
970
|
+
var bounds = [[${left}, ${top}], [${right}, ${top}], [${right}, ${bottom}], [${left}, ${bottom}]];
|
|
971
|
+
doc.selection.select(bounds);
|
|
972
|
+
|
|
973
|
+
return {
|
|
974
|
+
selection: 'rectangle',
|
|
975
|
+
bounds: [${left}, ${top}, ${right}, ${bottom}]
|
|
976
|
+
};
|
|
977
|
+
`,
|
|
978
|
+
/**
|
|
979
|
+
* Select all
|
|
980
|
+
*/
|
|
981
|
+
selectAll: () => `
|
|
982
|
+
if (app.documents.length === 0) {
|
|
983
|
+
throw new Error('No active document');
|
|
984
|
+
}
|
|
985
|
+
var doc = app.activeDocument;
|
|
986
|
+
doc.selection.selectAll();
|
|
987
|
+
|
|
988
|
+
return {
|
|
989
|
+
selection: 'all'
|
|
990
|
+
};
|
|
991
|
+
`,
|
|
992
|
+
/**
|
|
993
|
+
* Deselect
|
|
994
|
+
*/
|
|
995
|
+
deselect: () => `
|
|
996
|
+
if (app.documents.length === 0) {
|
|
997
|
+
throw new Error('No active document');
|
|
998
|
+
}
|
|
999
|
+
var doc = app.activeDocument;
|
|
1000
|
+
doc.selection.deselect();
|
|
1001
|
+
|
|
1002
|
+
return {
|
|
1003
|
+
deselected: true
|
|
1004
|
+
};
|
|
1005
|
+
`,
|
|
1006
|
+
/**
|
|
1007
|
+
* Invert selection
|
|
1008
|
+
*/
|
|
1009
|
+
invertSelection: () => `
|
|
1010
|
+
if (app.documents.length === 0) {
|
|
1011
|
+
throw new Error('No active document');
|
|
1012
|
+
}
|
|
1013
|
+
var doc = app.activeDocument;
|
|
1014
|
+
doc.selection.invert();
|
|
1015
|
+
|
|
1016
|
+
return {
|
|
1017
|
+
inverted: true
|
|
1018
|
+
};
|
|
1019
|
+
`,
|
|
1020
|
+
/**
|
|
1021
|
+
* Create layer mask from selection
|
|
1022
|
+
*/
|
|
1023
|
+
createLayerMask: () => `
|
|
1024
|
+
${helperFunctions}
|
|
1025
|
+
|
|
1026
|
+
if (app.documents.length === 0) {
|
|
1027
|
+
throw new Error('No active document');
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// Create mask using ActionDescriptor
|
|
1031
|
+
var desc = new ActionDescriptor();
|
|
1032
|
+
var ref = new ActionReference();
|
|
1033
|
+
ref.putEnumerated(cTID('Chnl'), cTID('Chnl'), cTID('Msk '));
|
|
1034
|
+
desc.putReference(cTID('Nw '), ref);
|
|
1035
|
+
desc.putEnumerated(cTID('Usng'), cTID('UsrM'), cTID('RvlS'));
|
|
1036
|
+
executeAction(cTID('Mk '), desc, DialogModes.NO);
|
|
1037
|
+
|
|
1038
|
+
return {
|
|
1039
|
+
maskCreated: true
|
|
1040
|
+
};
|
|
1041
|
+
`,
|
|
1042
|
+
/**
|
|
1043
|
+
* Delete layer mask
|
|
1044
|
+
*/
|
|
1045
|
+
deleteLayerMask: () => `
|
|
1046
|
+
${helperFunctions}
|
|
1047
|
+
|
|
1048
|
+
if (app.documents.length === 0) {
|
|
1049
|
+
throw new Error('No active document');
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
var desc = new ActionDescriptor();
|
|
1053
|
+
var ref = new ActionReference();
|
|
1054
|
+
ref.putEnumerated(cTID('Chnl'), cTID('Chnl'), cTID('Msk '));
|
|
1055
|
+
desc.putReference(cTID('null'), ref);
|
|
1056
|
+
executeAction(cTID('Dlt '), desc, DialogModes.NO);
|
|
1057
|
+
|
|
1058
|
+
return {
|
|
1059
|
+
maskDeleted: true
|
|
1060
|
+
};
|
|
1061
|
+
`,
|
|
1062
|
+
/**
|
|
1063
|
+
* Apply layer mask
|
|
1064
|
+
*/
|
|
1065
|
+
applyLayerMask: () => `
|
|
1066
|
+
${helperFunctions}
|
|
1067
|
+
|
|
1068
|
+
if (app.documents.length === 0) {
|
|
1069
|
+
throw new Error('No active document');
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
var desc = new ActionDescriptor();
|
|
1073
|
+
var ref = new ActionReference();
|
|
1074
|
+
ref.putEnumerated(cTID('Chnl'), cTID('Chnl'), cTID('Msk '));
|
|
1075
|
+
desc.putReference(cTID('null'), ref);
|
|
1076
|
+
executeAction(cTID('Aply'), desc, DialogModes.NO);
|
|
1077
|
+
|
|
1078
|
+
return {
|
|
1079
|
+
maskApplied: true
|
|
1080
|
+
};
|
|
1081
|
+
`,
|
|
1082
|
+
/**
|
|
1083
|
+
* Play an action from Actions palette
|
|
1084
|
+
*/
|
|
1085
|
+
playAction: (actionName, actionSetName) => `
|
|
1086
|
+
app.doAction("${actionName.replace(/"/g, '\\"')}", "${actionSetName.replace(/"/g, '\\"')}");
|
|
1087
|
+
|
|
1088
|
+
return {
|
|
1089
|
+
action: '${actionName}',
|
|
1090
|
+
set: '${actionSetName}'
|
|
1091
|
+
};
|
|
1092
|
+
`,
|
|
1093
|
+
/**
|
|
1094
|
+
* Execute custom JavaScript code
|
|
1095
|
+
*/
|
|
1096
|
+
executeCustomScript: (code) => `
|
|
1097
|
+
${code}
|
|
1098
|
+
`,
|
|
1099
|
+
/**
|
|
1100
|
+
* Rasterize active layer
|
|
1101
|
+
*/
|
|
1102
|
+
rasterizeLayer: () => `
|
|
1103
|
+
if (app.documents.length === 0) {
|
|
1104
|
+
throw new Error('No active document');
|
|
1105
|
+
}
|
|
1106
|
+
var layer = app.activeDocument.activeLayer;
|
|
1107
|
+
|
|
1108
|
+
if (layer.kind === LayerKind.NORMAL) {
|
|
1109
|
+
return {
|
|
1110
|
+
message: 'Layer is already rasterized',
|
|
1111
|
+
kind: 'NORMAL'
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
var originalKind = String(layer.kind);
|
|
1116
|
+
layer.rasterize(RasterizeType.ENTIRELAYER);
|
|
1117
|
+
|
|
1118
|
+
return {
|
|
1119
|
+
rasterized: true,
|
|
1120
|
+
originalKind: originalKind,
|
|
1121
|
+
newKind: 'NORMAL'
|
|
1122
|
+
};
|
|
1123
|
+
`,
|
|
1124
|
+
/**
|
|
1125
|
+
* Undo last operation (step backward in history)
|
|
1126
|
+
*/
|
|
1127
|
+
undo: (steps = 1) => `
|
|
1128
|
+
${getContextInfo}
|
|
1129
|
+
|
|
1130
|
+
if (app.documents.length === 0) {
|
|
1131
|
+
throw new Error('No active document');
|
|
1132
|
+
}
|
|
1133
|
+
var doc = app.activeDocument;
|
|
1134
|
+
|
|
1135
|
+
// Get current history state index
|
|
1136
|
+
var currentIndex = -1;
|
|
1137
|
+
for (var i = 0; i < doc.historyStates.length; i++) {
|
|
1138
|
+
if (doc.historyStates[i] === doc.activeHistoryState) {
|
|
1139
|
+
currentIndex = i;
|
|
1140
|
+
break;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
if (currentIndex === -1) {
|
|
1145
|
+
throw new Error('Could not find current history state');
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// Calculate target index
|
|
1149
|
+
var targetIndex = Math.max(0, currentIndex - ${steps});
|
|
1150
|
+
|
|
1151
|
+
// Set active history state to go back
|
|
1152
|
+
if (targetIndex < doc.historyStates.length) {
|
|
1153
|
+
doc.activeHistoryState = doc.historyStates[targetIndex];
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
var result = {
|
|
1157
|
+
undone: true,
|
|
1158
|
+
steps: currentIndex - targetIndex,
|
|
1159
|
+
currentHistoryState: doc.activeHistoryState.name,
|
|
1160
|
+
remainingStates: currentIndex - targetIndex,
|
|
1161
|
+
context: getContextInfo()
|
|
1162
|
+
};
|
|
1163
|
+
return result;
|
|
1164
|
+
`,
|
|
1165
|
+
/**
|
|
1166
|
+
* Redo operation (step forward in history)
|
|
1167
|
+
*/
|
|
1168
|
+
redo: (steps = 1) => `
|
|
1169
|
+
${getContextInfo}
|
|
1170
|
+
|
|
1171
|
+
if (app.documents.length === 0) {
|
|
1172
|
+
throw new Error('No active document');
|
|
1173
|
+
}
|
|
1174
|
+
var doc = app.activeDocument;
|
|
1175
|
+
|
|
1176
|
+
// Get current history state index
|
|
1177
|
+
var currentIndex = -1;
|
|
1178
|
+
for (var i = 0; i < doc.historyStates.length; i++) {
|
|
1179
|
+
if (doc.historyStates[i] === doc.activeHistoryState) {
|
|
1180
|
+
currentIndex = i;
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
if (currentIndex === -1) {
|
|
1186
|
+
throw new Error('Could not find current history state');
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// Calculate target index
|
|
1190
|
+
var targetIndex = Math.min(doc.historyStates.length - 1, currentIndex + ${steps});
|
|
1191
|
+
|
|
1192
|
+
// Set active history state to go forward
|
|
1193
|
+
if (targetIndex >= 0) {
|
|
1194
|
+
doc.activeHistoryState = doc.historyStates[targetIndex];
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
var result = {
|
|
1198
|
+
redone: true,
|
|
1199
|
+
steps: targetIndex - currentIndex,
|
|
1200
|
+
currentHistoryState: doc.activeHistoryState.name,
|
|
1201
|
+
availableRedoSteps: doc.historyStates.length - 1 - targetIndex,
|
|
1202
|
+
context: getContextInfo()
|
|
1203
|
+
};
|
|
1204
|
+
return result;
|
|
1205
|
+
`,
|
|
1206
|
+
/**
|
|
1207
|
+
* Get history states
|
|
1208
|
+
*/
|
|
1209
|
+
getHistoryStates: () => `
|
|
1210
|
+
${getContextInfo}
|
|
1211
|
+
|
|
1212
|
+
if (app.documents.length === 0) {
|
|
1213
|
+
throw new Error('No active document');
|
|
1214
|
+
}
|
|
1215
|
+
var doc = app.activeDocument;
|
|
1216
|
+
|
|
1217
|
+
var states = [];
|
|
1218
|
+
var currentIndex = -1;
|
|
1219
|
+
|
|
1220
|
+
for (var i = 0; i < doc.historyStates.length; i++) {
|
|
1221
|
+
var state = doc.historyStates[i];
|
|
1222
|
+
states.push({
|
|
1223
|
+
name: state.name,
|
|
1224
|
+
snapshot: state.snapshot || false
|
|
1225
|
+
});
|
|
1226
|
+
|
|
1227
|
+
if (state === doc.activeHistoryState) {
|
|
1228
|
+
currentIndex = i;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
var result = {
|
|
1233
|
+
totalStates: states.length,
|
|
1234
|
+
currentIndex: currentIndex,
|
|
1235
|
+
currentState: currentIndex >= 0 ? states[currentIndex].name : 'Unknown',
|
|
1236
|
+
canUndo: currentIndex > 0,
|
|
1237
|
+
canRedo: currentIndex < states.length - 1,
|
|
1238
|
+
states: states,
|
|
1239
|
+
context: getContextInfo()
|
|
1240
|
+
};
|
|
1241
|
+
return result;
|
|
1242
|
+
`,
|
|
1243
|
+
/**
|
|
1244
|
+
* Move layer to specific position (reorder)
|
|
1245
|
+
*/
|
|
1246
|
+
moveLayerToPosition: (targetLayerName, position) => `
|
|
1247
|
+
${getContextInfo}
|
|
1248
|
+
|
|
1249
|
+
if (app.documents.length === 0) {
|
|
1250
|
+
throw new Error('No active document');
|
|
1251
|
+
}
|
|
1252
|
+
var doc = app.activeDocument;
|
|
1253
|
+
var activeLayer = doc.activeLayer;
|
|
1254
|
+
|
|
1255
|
+
// Find target layer
|
|
1256
|
+
var targetLayer = null;
|
|
1257
|
+
for (var i = 0; i < doc.layers.length; i++) {
|
|
1258
|
+
if (doc.layers[i].name === "${targetLayerName.replace(/"/g, '\\"')}") {
|
|
1259
|
+
targetLayer = doc.layers[i];
|
|
1260
|
+
break;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
if (!targetLayer) {
|
|
1265
|
+
throw new Error('Target layer not found: ${targetLayerName}');
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// Determine ElementPlacement
|
|
1269
|
+
var placement;
|
|
1270
|
+
if ("${position}" === "ABOVE") {
|
|
1271
|
+
placement = ElementPlacement.PLACEBEFORE;
|
|
1272
|
+
} else if ("${position}" === "BELOW") {
|
|
1273
|
+
placement = ElementPlacement.PLACEAFTER;
|
|
1274
|
+
} else if ("${position}" === "TOP") {
|
|
1275
|
+
placement = ElementPlacement.PLACEATBEGINNING;
|
|
1276
|
+
} else if ("${position}" === "BOTTOM") {
|
|
1277
|
+
placement = ElementPlacement.PLACEATEND;
|
|
1278
|
+
} else {
|
|
1279
|
+
throw new Error('Invalid position. Use: ABOVE, BELOW, TOP, or BOTTOM');
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
// Move the layer
|
|
1283
|
+
activeLayer.move(targetLayer, placement);
|
|
1284
|
+
|
|
1285
|
+
var result = {
|
|
1286
|
+
moved: true,
|
|
1287
|
+
layerName: activeLayer.name,
|
|
1288
|
+
position: "${position}",
|
|
1289
|
+
relativeTo: targetLayer.name,
|
|
1290
|
+
context: getContextInfo()
|
|
1291
|
+
};
|
|
1292
|
+
return result;
|
|
1293
|
+
`,
|
|
1294
|
+
/**
|
|
1295
|
+
* Move layer to top of layer stack
|
|
1296
|
+
*/
|
|
1297
|
+
moveLayerToTop: () => `
|
|
1298
|
+
${getContextInfo}
|
|
1299
|
+
|
|
1300
|
+
if (app.documents.length === 0) {
|
|
1301
|
+
throw new Error('No active document');
|
|
1302
|
+
}
|
|
1303
|
+
var doc = app.activeDocument;
|
|
1304
|
+
var layer = doc.activeLayer;
|
|
1305
|
+
|
|
1306
|
+
if (doc.layers.length > 0) {
|
|
1307
|
+
layer.move(doc.layers[0], ElementPlacement.PLACEBEFORE);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
var result = {
|
|
1311
|
+
moved: true,
|
|
1312
|
+
layerName: layer.name,
|
|
1313
|
+
position: 'top',
|
|
1314
|
+
context: getContextInfo()
|
|
1315
|
+
};
|
|
1316
|
+
return result;
|
|
1317
|
+
`,
|
|
1318
|
+
/**
|
|
1319
|
+
* Move layer to bottom of layer stack
|
|
1320
|
+
*/
|
|
1321
|
+
moveLayerToBottom: () => `
|
|
1322
|
+
${getContextInfo}
|
|
1323
|
+
|
|
1324
|
+
if (app.documents.length === 0) {
|
|
1325
|
+
throw new Error('No active document');
|
|
1326
|
+
}
|
|
1327
|
+
var doc = app.activeDocument;
|
|
1328
|
+
var layer = doc.activeLayer;
|
|
1329
|
+
|
|
1330
|
+
if (doc.layers.length > 0) {
|
|
1331
|
+
layer.move(doc.layers[doc.layers.length - 1], ElementPlacement.PLACEAFTER);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
var result = {
|
|
1335
|
+
moved: true,
|
|
1336
|
+
layerName: layer.name,
|
|
1337
|
+
position: 'bottom',
|
|
1338
|
+
context: getContextInfo()
|
|
1339
|
+
};
|
|
1340
|
+
return result;
|
|
1341
|
+
`,
|
|
1342
|
+
/**
|
|
1343
|
+
* Move layer up one position
|
|
1344
|
+
*/
|
|
1345
|
+
moveLayerUp: () => `
|
|
1346
|
+
${getContextInfo}
|
|
1347
|
+
|
|
1348
|
+
if (app.documents.length === 0) {
|
|
1349
|
+
throw new Error('No active document');
|
|
1350
|
+
}
|
|
1351
|
+
var doc = app.activeDocument;
|
|
1352
|
+
var layer = doc.activeLayer;
|
|
1353
|
+
|
|
1354
|
+
// Find current layer index
|
|
1355
|
+
var currentIndex = -1;
|
|
1356
|
+
for (var i = 0; i < doc.layers.length; i++) {
|
|
1357
|
+
if (doc.layers[i] === layer) {
|
|
1358
|
+
currentIndex = i;
|
|
1359
|
+
break;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
if (currentIndex <= 0) {
|
|
1364
|
+
return {
|
|
1365
|
+
moved: false,
|
|
1366
|
+
message: 'Layer is already at the top',
|
|
1367
|
+
context: getContextInfo()
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// Move before the layer above
|
|
1372
|
+
layer.move(doc.layers[currentIndex - 1], ElementPlacement.PLACEBEFORE);
|
|
1373
|
+
|
|
1374
|
+
var result = {
|
|
1375
|
+
moved: true,
|
|
1376
|
+
layerName: layer.name,
|
|
1377
|
+
direction: 'up',
|
|
1378
|
+
context: getContextInfo()
|
|
1379
|
+
};
|
|
1380
|
+
return result;
|
|
1381
|
+
`,
|
|
1382
|
+
/**
|
|
1383
|
+
* Move layer down one position
|
|
1384
|
+
*/
|
|
1385
|
+
moveLayerDown: () => `
|
|
1386
|
+
${getContextInfo}
|
|
1387
|
+
|
|
1388
|
+
if (app.documents.length === 0) {
|
|
1389
|
+
throw new Error('No active document');
|
|
1390
|
+
}
|
|
1391
|
+
var doc = app.activeDocument;
|
|
1392
|
+
var layer = doc.activeLayer;
|
|
1393
|
+
|
|
1394
|
+
// Find current layer index
|
|
1395
|
+
var currentIndex = -1;
|
|
1396
|
+
for (var i = 0; i < doc.layers.length; i++) {
|
|
1397
|
+
if (doc.layers[i] === layer) {
|
|
1398
|
+
currentIndex = i;
|
|
1399
|
+
break;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
if (currentIndex === -1 || currentIndex >= doc.layers.length - 1) {
|
|
1404
|
+
return {
|
|
1405
|
+
moved: false,
|
|
1406
|
+
message: 'Layer is already at the bottom',
|
|
1407
|
+
context: getContextInfo()
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
// Move after the layer below
|
|
1412
|
+
layer.move(doc.layers[currentIndex + 1], ElementPlacement.PLACEAFTER);
|
|
1413
|
+
|
|
1414
|
+
var result = {
|
|
1415
|
+
moved: true,
|
|
1416
|
+
layerName: layer.name,
|
|
1417
|
+
direction: 'down',
|
|
1418
|
+
context: getContextInfo()
|
|
1419
|
+
};
|
|
1420
|
+
return result;
|
|
1421
|
+
`,
|
|
1422
|
+
};
|
|
1423
|
+
/**
|
|
1424
|
+
* Generate ExtendScript code with error handling
|
|
1425
|
+
*/
|
|
1426
|
+
export function generateExtendScript(code) {
|
|
1427
|
+
return `
|
|
1428
|
+
(function() {
|
|
1429
|
+
try {
|
|
1430
|
+
${code}
|
|
1431
|
+
} catch (error) {
|
|
1432
|
+
return 'ERROR: ' + (error.message || String(error));
|
|
1433
|
+
}
|
|
1434
|
+
})();
|
|
1435
|
+
`.trim();
|
|
1436
|
+
}
|
|
1437
|
+
//# sourceMappingURL=extendscript.js.map
|