';
415 | html.write(htmlBody);
416 | html.close();
417 | html.execute();
418 | }
419 |
420 | try {
421 | main();
422 | } catch(err) {}
--------------------------------------------------------------------------------
/jsx/ClearLayer.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | ClearLayer.jsx for Adobe Photoshop
3 | Description: Simple script to clear layers content.
4 | Date: June, 2019
5 | Author: Sergey Osokin, email: hi@sergosokin.ru
6 |
7 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
8 |
9 | Donate (optional):
10 | If you find this script helpful, you can buy me a coffee
11 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
12 | - via Donatty https://donatty.com/sergosokin
13 | - via DonatePay https://new.donatepay.ru/en/@osokin
14 | - via YooMoney https://yoomoney.ru/to/410011149615582
15 |
16 | NOTICE:
17 | Tested with Adobe Photoshop CC 2019-2022.
18 | This script is provided "as is" without warranty of any kind.
19 | Free to use, not for sale
20 |
21 | Released under the MIT license.
22 | http://opensource.org/licenses/mit-license.php
23 |
24 | Check my other scripts: https://github.com/creold
25 | */
26 |
27 | //@target photoshop
28 |
29 | app.bringToFront();
30 |
31 | function main() {
32 | var doc = app.activeDocument;
33 | var selLayers = getSelectedLayersIdx();
34 | for (var i = 0; i < selLayers.length; i++) {
35 | makeActiveByIndex(selLayers[i], false);
36 | doc.activeLayer.clear();
37 | }
38 | }
39 |
40 | // This solution by geppettol66959005
41 | // https://community.adobe.com/t5/photoshop/how-to-find-selected-layers-and-run-events/td-p/10269273?page=1
42 | function getSelectedLayersIdx() {
43 | var selectedLayers = new Array
44 | var ref = new ActionReference()
45 | ref.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"))
46 | var desc = executeActionGet(ref)
47 | if (desc.hasKey(stringIDToTypeID('targetLayers'))){
48 | desc = desc.getList(stringIDToTypeID('targetLayers'))
49 | var selectedLayers = new Array()
50 | for (var i = 0; i < desc.count; i++){
51 | try {
52 | activeDocument.backgroundLayer
53 | selectedLayers.push(desc.getReference(i).getIndex())
54 | } catch (e) {
55 | selectedLayers.push(desc.getReference(i).getIndex() + 1)
56 | }
57 | }
58 | } else {
59 | var ref = new ActionReference()
60 | ref.putProperty(charIDToTypeID("Prpr"), charIDToTypeID("ItmI"));
61 | ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
62 | try{
63 | activeDocument.backgroundLayer
64 | selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID("ItmI")) - 1);
65 | } catch (e) {
66 | selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID("ItmI")))
67 | }
68 | }
69 | return selectedLayers
70 | }
71 |
72 | function makeActiveByIndex(idx, visible) {
73 | var desc = new ActionDescriptor()
74 | var ref = new ActionReference()
75 | ref.putIndex(charIDToTypeID("Lyr "), idx)
76 | desc.putReference(charIDToTypeID("null"), ref)
77 | desc.putBoolean(charIDToTypeID("MkVs"), visible)
78 | executeAction(charIDToTypeID("slct"), desc, DialogModes.NO)
79 | }
80 |
81 | // Run script
82 | try {
83 | app.activeDocument.suspendHistory('Clear Layers Script', 'main()');
84 | } catch (e) { }
--------------------------------------------------------------------------------
/jsx/ExportPathsToAi.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | ExportPathsToAi.jsx for Adobe Photoshop
3 | Description: Export all visible vector layers as unfilled paths to Illustrator
4 | Date: August, 2022
5 | Author: Sergey Osokin, email: hi@sergosokin.ru
6 |
7 | Original idea:
8 | https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-export-paths-to-ai-in-action-batch/td-p/11049168
9 |
10 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
11 |
12 | Release notes:
13 | 0.1 Initial version by Stephen_A_Marsh
14 | 0.2 Added one-click export of all vector paths
15 |
16 | Donate (optional):
17 | If you find this script helpful, you can buy me a coffee
18 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
19 | - via Donatty https://donatty.com/sergosokin
20 | - via DonatePay https://new.donatepay.ru/en/@osokin
21 | - via YooMoney https://yoomoney.ru/to/410011149615582
22 |
23 | NOTICE:
24 | Tested with Adobe Photoshop CC 2019-2022.
25 | This script is provided "as is" without warranty of any kind.
26 | Free to use, not for sale
27 |
28 | Released under the MIT license
29 | http://opensource.org/licenses/mit-license.php
30 |
31 | Check my other scripts: https://github.com/creold
32 | */
33 |
34 | //@target photoshop
35 |
36 | function main() {
37 | if (!isCorrectEnv()) return;
38 |
39 | var doc = activeDocument,
40 | docName = doc.name.replace(/\.[^\.]+$/, ''),
41 | shapes = getVisShapes(doc), // Array of layer ID's
42 | outFolder;
43 |
44 | try {
45 | outFolder = doc.path;
46 | } catch (e) {
47 | outFolder = Folder.desktop;
48 | }
49 |
50 | if (!shapes.length) {
51 | alert('Visible vector layers have not been found');
52 | return;
53 | }
54 |
55 | deselect();
56 |
57 | for (var i = 0; i < shapes.length; i++) {
58 | selectByID(shapes[i]);
59 | }
60 |
61 | var result = exportPaths(outFolder, docName, '.ai');
62 | if (result) {
63 | alert(shapes.length + ' visible vector layers have been exported to ' + '\n' + decodeURI(result));
64 | }
65 | }
66 |
67 | // Check the script environment
68 | function isCorrectEnv() {
69 | var args = ['app', 'document'];
70 |
71 | for (var i = 0; i < args.length; i++) {
72 | switch (args[i].toString().toLowerCase()) {
73 | case 'app':
74 | if (!/photoshop/i.test(app.name)) {
75 | alert('Error\nRun script from Adobe Photoshop');
76 | return false;
77 | }
78 | break;
79 | case 'document':
80 | if (!documents.length) {
81 | alert('Error\nOpen a document and try again');
82 | return false;
83 | }
84 | break;
85 | }
86 | }
87 |
88 | return true;
89 | }
90 |
91 | // Get indexes of all visible vector layers
92 | function getVisShapes(collection) {
93 | var out = [];
94 |
95 | for (var i = 0; i < collection.layers.length; i++) {
96 | var lyr = collection.layers[i];
97 | if (!lyr.visible) continue;
98 | if (/art/i.test(lyr.typename)) {
99 | if (isType(lyr, 4)) out.push(lyr.id); // const kVectorSheet = 4;
100 | } else if (/set/i.test(lyr.typename)) {
101 | out = [].concat(out, getVisShapes(lyr));
102 | } else {
103 | out = [].concat(out, getVisShapes(lyr));
104 | }
105 | }
106 |
107 | return out;
108 | }
109 |
110 | // Check LayerKind code
111 | function isType(layer, code) {
112 | try {
113 | activeDocument.activeLayer = layer;
114 | } catch (e) {}
115 |
116 | var ref = new ActionReference();
117 | ref.putProperty(sTID('property'), sTID('layerKind'));
118 | ref.putEnumerated(sTID('layer'), sTID('ordinal'), sTID('targetEnum'));
119 | var type = executeActionGet(ref).getInteger(sTID('layerKind'));
120 |
121 | return type == code;
122 | }
123 |
124 | function cTID(s) {
125 | return app.charIDToTypeID(s);
126 | }
127 |
128 | function sTID(s) {
129 | return app.stringIDToTypeID(s);
130 | }
131 |
132 | // Deselect all layers in the document
133 | function deselect() {
134 | var ref = new ActionReference(),
135 | desc = new ActionDescriptor();
136 |
137 | ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID('Trgt') );
138 | desc.putReference(cTID('null'), ref);
139 | executeAction(sTID('selectNoLayers'), desc, DialogModes.NO);
140 | }
141 |
142 | // Select layer by index
143 | function selectByID(id) {
144 | var ref = new ActionReference(),
145 | desc = new ActionDescriptor();
146 |
147 | ref.putIdentifier(cTID('Lyr '), id);
148 | desc.putReference(cTID('null'), ref);
149 | desc.putEnumerated(sTID('selectionModifier'), sTID('selectionModifierType'), sTID('addToSelection'));
150 | desc.putBoolean(cTID('MkVs'), false);
151 | executeAction(cTID('slct'), desc, DialogModes.NO);
152 | }
153 |
154 | // Export vector paths to Illustrator file
155 | function exportPaths(folder, name, ext) {
156 | try {
157 | var aiFile = new File(folder + '/' + name + ext),
158 | expOptions = new ExportOptionsIllustrator;
159 |
160 | expOptions.path = IllustratorPathType.ALLPATHS;
161 | activeDocument.exportDocument(aiFile, ExportType.ILLUSTRATORPATHS, expOptions);
162 | return aiFile;
163 | } catch (e) {
164 | return null;
165 | }
166 | }
167 |
168 | try {
169 | main();
170 | } catch(e) {}
--------------------------------------------------------------------------------
/jsx/GeneratePreview.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | GeneratePreview.jsx for Adobe Photoshop
3 | Description: Generate JPG preview image from active document.
4 | Date: October, 2018
5 | Author: Sergey Osokin, email: hi@sergosokin.ru
6 |
7 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
8 |
9 | Donate (optional):
10 | If you find this script helpful, you can buy me a coffee
11 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
12 | - via Donatty https://donatty.com/sergosokin
13 | - via DonatePay https://new.donatepay.ru/en/@osokin
14 | - via YooMoney https://yoomoney.ru/to/410011149615582
15 |
16 | NOTICE:
17 | Tested with Adobe Photoshop CC 2019-2022.
18 | This script is provided "as is" without warranty of any kind.
19 | Free to use, not for sale
20 |
21 | Released under the MIT license.
22 | http://opensource.org/licenses/mit-license.php
23 |
24 | Check my other scripts: https://github.com/creold
25 | */
26 |
27 | //@target photoshop
28 |
29 | if (app.documents.length > 0) {
30 | var fName = app.activeDocument.name;
31 | var fileExt = '.jpg';
32 | var jpegSizeMax = 1200; // for resizeDoc() function. Unit: px
33 | var newName = prepareName(app.activeDocument);
34 | var savePath = '';
35 | // File path for saved doc
36 | try {
37 | savePath = app.activeDocument.path;
38 | } catch (e) {
39 | // File path for unsaved doc
40 | savePath = Folder.selectDialog('Select the folder for save preview image');
41 | }
42 | }
43 |
44 | // Main function
45 | function main() {
46 | duplicateDoc(); // Duplicate Image
47 | clearAllGuides(); // Remove all guides from duplicate
48 | var doc = app.activeDocument;
49 | doc.flatten(); // Flatten Image
50 | resizeDoc(doc, jpegSizeMax); // Resize image to specific size
51 | doc.changeMode(ChangeMode.RGB); // Convert Image Mode to RGB
52 | if (savePath != null) {
53 | var fileName = decodeURI(savePath) + '/' + newName;
54 | exportJPG(doc, fileName, fileExt);
55 | }
56 | doc.close(SaveOptions.DONOTSAVECHANGES); // Close duplicate
57 | };
58 |
59 | function prepareName(doc) {
60 | var name = decodeURI(doc.name);
61 | name = name.replace(/\s/g, '-'); // Replace all space symbols
62 | var lastDotPosition = name.lastIndexOf('.');
63 | if (lastDotPosition > -1) {
64 | return name.slice(0, lastDotPosition); // Remove filename extension
65 | }
66 | return name;
67 | }
68 |
69 | // Duplicate Image
70 | function duplicateDoc(enabled, withDialog) {
71 | if (enabled != undefined && !enabled) return;
72 | var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
73 | var desc1 = new ActionDescriptor();
74 | var ref1 = new ActionReference();
75 | ref1.putEnumerated(charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Frst'));
76 | desc1.putReference(charIDToTypeID('null'), ref1);
77 | executeAction(charIDToTypeID('Dplc'), desc1, dialogMode);
78 | }
79 |
80 | // Remove all guides from duplicate
81 | function clearAllGuides(enabled, withDialog) {
82 | if (enabled != undefined && !enabled) return;
83 | var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
84 | var desc = new ActionDescriptor();
85 | var ref = new ActionReference();
86 | ref.putEnumerated(charIDToTypeID('Gd '), charIDToTypeID('Ordn'), charIDToTypeID('Al '));
87 | desc.putReference(charIDToTypeID('null'), ref);
88 | executeAction(charIDToTypeID('Dlt '), desc, dialogMode);
89 | }
90 |
91 | // Resize image to specific size
92 | function resizeDoc(doc, size) {
93 | // If height > width resize based on height. Change DPI to 72
94 | app.preferences.rulerUnits = Units.PIXELS;
95 | if (doc.height.value > size || doc.width.value > size) {
96 | if (doc.height > doc.width) {
97 | doc.resizeImage(null, UnitValue(size, 'px'), 72, ResampleMethod.BICUBIC);
98 | } else {
99 | doc.resizeImage(UnitValue(size, 'px'), null, 72, ResampleMethod.BICUBIC);
100 | }
101 | }
102 | }
103 |
104 | function exportJPG(doc, fileName, ext) {
105 | // Web export options
106 | var options = new ExportOptionsSaveForWeb();
107 | options.quality = 85;
108 | options.format = SaveDocumentType.JPEG;
109 | options.optimized = true;
110 |
111 | var file = File(fileName + ext);
112 | var msg = 'A file with the same name already exists in the folder "' + decodeURI(file.parent.name) + '". Replacing it will overwrite its current contents.';
113 | if (file.exists) {
114 | var rewrite = confirm('"' + decodeURI(file.name) + '" already exists. Do you want to replace it?\n' + msg);
115 | if (!rewrite) {
116 | var counter = 2;
117 | do {
118 | var newName = fileName + '-' + fillZero(counter++, 2);
119 | file = File(newName + ext);
120 | } while (file.exists)
121 | }
122 | }
123 | doc.exportDocument(file, ExportType.SAVEFORWEB, options);
124 | alert('The file saved as:\n' + decodeURI(file.name));
125 | }
126 |
127 | // Add zero to the file name before the indexes are less then size
128 | function fillZero(number, size) {
129 | var str = '000000000' + number;
130 | return str.slice(str.length - size);
131 | }
132 |
133 | // Run script
134 | try {
135 | main();
136 | } catch (e) { }
--------------------------------------------------------------------------------
/jsx/MultiEditText.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | MultiEditText.jsx for Adobe Photoshop
3 | Description: Bulk editing of text layer contents. Replaces content separately or with the same text
4 | Date: April, 2024
5 | Modification date: February, 2025
6 | Author: Sergey Osokin, email: hi@sergosokin.ru
7 |
8 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
9 |
10 | *******************************************************************************************
11 | * WARNING: The script does not support the mixed appearance of characters in a text layer *
12 | *******************************************************************************************
13 |
14 | Release notes:
15 | 0.2 Added button to reset texts, saving entered texts when switching options
16 | 0.1 Initial version
17 |
18 | Donate (optional):
19 | If you find this script helpful, you can buy me a coffee
20 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
21 | - via Donatty https://donatty.com/sergosokin
22 | - via DonatePay https://new.donatepay.ru/en/@osokin
23 | - via YooMoney https://yoomoney.ru/to/410011149615582
24 |
25 | NOTICE:
26 | Tested with Adobe Photoshop CC 2019, 2024 (Mac/Win).
27 | This script is provided "as is" without warranty of any kind.
28 | Free to use, not for sale
29 |
30 | Released under the MIT license
31 | http://opensource.org/licenses/mit-license.php
32 |
33 | Check my other scripts: https://github.com/creold
34 | */
35 |
36 | //@target photoshop
37 |
38 | function main() {
39 | var SCRIPT = {
40 | name: 'Multi-edit Text',
41 | version: 'v0.2'
42 | };
43 |
44 | var CFG = {
45 | width: 300, // Text area width, px
46 | height: 240, // Text area height, px
47 | ph: ' ';
499 | html.write(htmlBody);
500 | html.close();
501 | html.execute();
502 | }
503 |
504 | try {
505 | if (!/photoshop/i.test(app.name)) {
506 | alert('Error\nRun script from Adobe Photoshop');
507 | } else if (!documents.length) {
508 | alert('Error\nOpen a document and try again');
509 | } else {
510 | app.activeDocument.suspendHistory('Multi-edit Text', 'main()');
511 | }
512 | } catch (err) {}
--------------------------------------------------------------------------------
/jsx/RenameArtboardAsSize.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | RenameArtboardAsSize.jsx for Adobe Photoshop
3 | Description: The script renames artboards according to their size in units from Preferences > Units & Rulers
4 | Date: January, 2024
5 | Author: Sergey Osokin, email: hi@sergosokin.ru
6 |
7 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
8 |
9 | Release notes:
10 | 0.1 Initial version
11 | 0.1.1 Fixed convertUnits() function
12 |
13 | Donate (optional):
14 | If you find this script helpful, you can buy me a coffee
15 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
16 | - via Donatty https://donatty.com/sergosokin
17 | - via DonatePay https://new.donatepay.ru/en/@osokin
18 | - via YooMoney https://yoomoney.ru/to/410011149615582
19 |
20 | NOTICE:
21 | Tested with Adobe Photoshop CC 2019, 2024 (Mac OS).
22 | This script is provided "as is" without warranty of any kind.
23 | Free to use, not for sale
24 |
25 | Released under the MIT license
26 | http://opensource.org/licenses/mit-license.php
27 |
28 | Check my other scripts: https://github.com/creold
29 | */
30 |
31 | //@target photoshop
32 | app.bringToFront();
33 |
34 | function main() {
35 | var CFG = {
36 | units: getUnits(), // Active document units
37 | isSaveName: true, // Set false to overwrite the full name
38 | isRound: true, // Set true to get a round number
39 | precision: 2, // Size rounding precision
40 | isAddUnit: true,
41 | separator: '_',
42 | settings: 'RAAS_settings',
43 | };
44 |
45 | if (!isCorrectEnv()) return;
46 |
47 | if (!app.activeDocument.layerSets.length) {
48 | alert("The document doesn't seem to have artboards", 'Script Error');
49 | return;
50 | }
51 |
52 | invokeUI(CFG);
53 | }
54 |
55 | // Show UI
56 | function invokeUI(prefs) {
57 | var doc = app.activeDocument;
58 |
59 | var win = new Window('dialog', 'Rename Artboard As Size');
60 | win.alignChildren = ['fill', 'fill'];
61 |
62 | // Range
63 | var rangePnl = win.add('panel', undefined, 'Artboards range');
64 | rangePnl.alignChildren = ['fill', 'center'];
65 | rangePnl.margins = [12, 14, 10, 14];
66 |
67 | var isAll = rangePnl.add('radiobutton', undefined, 'All artboards');
68 | isAll.value = true;
69 |
70 | var isCurr = rangePnl.add('radiobutton', undefined, 'Active artboard');
71 |
72 | // Options
73 | var optPnl = win.add('panel', undefined, 'Options');
74 | optPnl.alignChildren = ['fill', 'center'];
75 | optPnl.margins = [12, 14, 10, 14];
76 |
77 | var isSaveName = optPnl.add('checkbox', undefined, 'Add size as suffix');
78 | isSaveName.value = prefs.isSaveName;
79 |
80 | var isRound = optPnl.add('checkbox', undefined, 'Round to integer');
81 | isRound.value = prefs.isRound;
82 |
83 | var isAddUnit = optPnl.add('checkbox', undefined, 'Add units after size');
84 | isAddUnit.value = prefs.isAddUnit;
85 |
86 | // Buttons
87 | var btns = win.add('group');
88 | btns.alignChildren = ['fill', 'center'];
89 |
90 | var cancel, ok;
91 | if (/mac/i.test($.os)) {
92 | cancel = btns.add('button', undefined, 'Cancel', { name: 'cancel' });
93 | ok = btns.add('button', undefined, 'OK', { name: 'ok' });
94 | } else {
95 | ok = btns.add('button', undefined, 'OK', { name: 'ok' });
96 | cancel = btns.add('button', undefined, 'Cancel', { name: 'cancel' });
97 | }
98 | cancel.helpTip = 'Press Esc to Close';
99 | ok.helpTip = 'Press Enter to Run';
100 |
101 | var copyright = win.add('statictext', undefined, '\u00A9 Sergey Osokin. Visit Github');
102 | copyright.justify = 'center';
103 |
104 | loadSettings();
105 |
106 | copyright.addEventListener('mousedown', function () {
107 | openURL('https://github.com/creold');
108 | });
109 |
110 | cancel.onClick = win.close;
111 |
112 | ok.onClick = function () {
113 | doc.suspendHistory('Rename Artboards', 'okClick()');
114 | }
115 |
116 | function okClick() {
117 | var doc = app.activeDocument;
118 | var range = isAll.value ? doc.layerSets : [doc.activeLayer];
119 |
120 | prefs.isSaveName = isSaveName.value;
121 | prefs.isRound = isRound.value;
122 | prefs.isAddUnit = isAddUnit.value;
123 |
124 | for (var i = 0, len = range.length; i < len; i++) {
125 | renameArtboard(range[i], prefs);
126 | }
127 |
128 | saveSettings();
129 | win.close();
130 | }
131 |
132 | function loadSettings() {
133 | try {
134 | var desc = app.getCustomOptions(prefs.settings);
135 | } catch (err) {}
136 | if (typeof desc != 'undefined') {
137 | try {
138 | rangePnl.children[desc.getInteger(0)].value = true;
139 | isSaveName.value = desc.getBoolean(1);
140 | isRound.value = desc.getBoolean(2);
141 | isAddUnit.value = desc.getBoolean(3);
142 | return;
143 | } catch (err) {}
144 | }
145 |
146 | compressPref = true;
147 | }
148 |
149 | function saveSettings() {
150 | var desc = new ActionDescriptor();
151 | desc.putInteger(0, isAll.value ? 0 : 1);
152 | desc.putBoolean(1, isSaveName.value);
153 | desc.putBoolean(2, isRound.value);
154 | desc.putBoolean(3, isAddUnit.value);
155 | app.putCustomOptions(prefs.settings, desc, true);
156 | }
157 |
158 | win.center();
159 | win.show();
160 | }
161 |
162 | // Rename an artboard by its size
163 | function renameArtboard(ab, prefs) {
164 | var abName = ab.name;
165 | var separator = /\s/.test(abName) ? ' ' : (/-/.test(abName) ? '-' : prefs.separator);
166 |
167 | var abRect = getArtboardSize(ab);
168 |
169 | var width = convertUnits(abRect[2] - abRect[0], 'px', prefs.units);
170 | var height = convertUnits(abRect[3] - abRect[1], 'px', prefs.units);
171 |
172 | // It's probably a group of layers
173 | if (width === 0 || height === 0) return;
174 |
175 | width = prefs.isRound ? Math.round(width) : width.toFixed(prefs.precision);
176 | height = prefs.isRound ? Math.round(height) : height.toFixed(prefs.precision);
177 |
178 | var size = width + 'x' + height;
179 | if (prefs.isAddUnit) size += prefs.units;
180 |
181 | if (prefs.isSaveName) {
182 | ab.name += separator + size;
183 | } else {
184 | ab.name = size;
185 | }
186 | }
187 |
188 | // Get ruler units
189 | function getUnits() {
190 | var units = 'px';
191 | var ruler = app.preferences.rulerUnits.toString();
192 | var key = ruler.replace('Units.', '');
193 |
194 | switch (key) {
195 | case 'PIXELS': units = 'px'; break;
196 | case 'INCHES': units = 'in'; break;
197 | case 'CM': units = 'cm'; break;
198 | case 'MM': units = 'mm'; break;
199 | case 'POINTS': units = 'pt'; break;
200 | case 'PICAS': units = 'pc'; break;
201 | case 'PERCENT': units = 'px'; break;
202 | }
203 |
204 | return units;
205 | }
206 |
207 | // Check the script environment
208 | function isCorrectEnv() {
209 | var args = ['app', 'document'];
210 |
211 | for (var i = 0; i < args.length; i++) {
212 | switch (args[i].toString().toLowerCase()) {
213 | case 'app':
214 | if (!/photoshop/i.test(app.name)) {
215 | alert('Wrong application\nRun script from Adobe Photoshop', 'Script error');
216 | return false;
217 | }
218 | break;
219 | case 'document':
220 | if (!documents.length) {
221 | alert('No documents\nOpen a document and try again', 'Script error');
222 | return false;
223 | }
224 | break;
225 | }
226 | }
227 |
228 | return true;
229 | }
230 |
231 | // Get artboard dimensions (artboar has type LayerSet) by Chuck Uebele
232 | // https://community.adobe.com/t5/photoshop-ecosystem-discussions/photoshop-scripting-artboard-size-values/m-p/13256092#M677004
233 | function getArtboardSize(layer) {
234 | try {
235 | var ref = new ActionReference();
236 | ref.putProperty(sTID('property'), sTID('artboard'));
237 | if (layer) {
238 | ref.putIdentifier(sTID('layer'), layer.id);
239 | } else {
240 | ref.putEnumerated(sTID('layer'), sTID('ordinal'), sTID('targetEnum'));
241 | }
242 |
243 | var desc = executeActionGet(ref).getObjectValue(sTID('artboard')).getObjectValue(sTID('artboardRect'));
244 | var bounds = [];
245 | bounds[0] = desc.getUnitDoubleValue(sTID('left'));
246 | bounds[1] = desc.getUnitDoubleValue(sTID('top'));
247 | bounds[2] = desc.getUnitDoubleValue(sTID('right'));
248 | bounds[3] = desc.getUnitDoubleValue(sTID('bottom'));
249 |
250 | return bounds;
251 | } catch(err) {
252 | return [0, 0, 0, 0];
253 | }
254 | }
255 |
256 | function sTID(s) {
257 | return app.stringIDToTypeID(s);
258 | }
259 |
260 | // Convert units of measurement
261 | function convertUnits(value, currUnits, newUnits) {
262 | UnitValue.baseUnit = UnitValue (1 / activeDocument.resolution, 'in');
263 | var newValue = new UnitValue(value, currUnits);
264 | newValue = newValue.as(newUnits);
265 | UnitValue.baseUnit = null;
266 | return newValue;
267 | }
268 |
269 |
270 | // Open link in browser
271 | function openURL(url) {
272 | var html = new File(Folder.temp.absoluteURI + '/aisLink.html');
273 | html.open('w');
274 | var htmlBody = ' ';
275 | html.write(htmlBody);
276 | html.close();
277 | html.execute();
278 | }
279 |
280 | try {
281 | main();
282 | } catch(err) {}
--------------------------------------------------------------------------------
/jsx/SaveAll.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | SaveAll.jsx for Adobe Photoshop
3 | Description: Simple script to save all opened docs.
4 | Date: October, 2018
5 | Author: Sergey Osokin, email: hi@sergosokin.ru
6 |
7 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
8 |
9 | Donate (optional):
10 | If you find this script helpful, you can buy me a coffee
11 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
12 | - via Donatty https://donatty.com/sergosokin
13 | - via DonatePay https://new.donatepay.ru/en/@osokin
14 | - via YooMoney https://yoomoney.ru/to/410011149615582
15 |
16 | NOTICE:
17 | Tested with Adobe Photoshop CC 2019-2022.
18 | This script is provided "as is" without warranty of any kind.
19 | Free to use, not for sale
20 |
21 | Released under the MIT license
22 | http://opensource.org/licenses/mit-license.php
23 |
24 | Check my other scripts: https://github.com/creold
25 | */
26 |
27 | //@target photoshop
28 |
29 | var tempDoc = app.activeDocument;
30 |
31 | for (var i = app.documents.length - 1; i >= 0; i--) {
32 | var currDoc = app.documents[i];
33 | // TRY..CATCH function for unsaved document
34 | try {
35 | if (!currDoc.saved) {
36 | app.activeDocument = currDoc;
37 | currDoc.save();
38 | }
39 | } catch (e) {}
40 | }
41 |
42 | app.activeDocument = tempDoc;
--------------------------------------------------------------------------------
/jsx/SelectShapesByColor.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | SelectShapesByColor.jsx for Adobe Photoshop
3 | Description: Select all Shape and Solid layers that have the same color as the selected layer
4 | Date: April, 2022
5 | Author: Sergey Osokin, email: hi@sergosokin.ru
6 |
7 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
8 |
9 | Release notes:
10 | 0.1 Initial version
11 | 0.2 Added live text support
12 |
13 | Donate (optional):
14 | If you find this script helpful, you can buy me a coffee
15 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
16 | - via Donatty https://donatty.com/sergosokin
17 | - via DonatePay https://new.donatepay.ru/en/@osokin
18 | - via YooMoney https://yoomoney.ru/to/410011149615582
19 |
20 | NOTICE:
21 | Tested with Adobe Photoshop CC 2019-2022.
22 | This script is provided "as is" without warranty of any kind.
23 | Free to use, not for sale
24 |
25 | Released under the MIT license
26 | http://opensource.org/licenses/mit-license.php
27 |
28 | Check my other scripts: https://github.com/creold
29 | */
30 |
31 | //@target photoshop
32 |
33 | function main() {
34 | if (!isCorrectEnv()) return;
35 |
36 | var inclSolid = false; // Include Adjustment Layer > Solid Color to selection
37 |
38 | var aLayer = activeDocument.activeLayer;
39 | if (!aLayer.visible) return;
40 |
41 | var sample = getColor(aLayer), // Hex
42 | matches = search(sample, inclSolid); // Array of layer ID's
43 |
44 | deselect();
45 |
46 | forEach(matches, function (e) {
47 | selectByID(e);
48 | });
49 | }
50 |
51 | // Check the script environment
52 | function isCorrectEnv() {
53 | var args = ['app', 'document'];
54 |
55 | for (var i = 0; i < args.length; i++) {
56 | switch (args[i].toString().toLowerCase()) {
57 | case 'app':
58 | if (!/photoshop/i.test(app.name)) {
59 | alert('Error\nRun script from Adobe Photoshop');
60 | return false;
61 | }
62 | break;
63 | case 'document':
64 | if (!documents.length) {
65 | alert('Error\nOpen a document and try again');
66 | return false;
67 | }
68 | break;
69 | }
70 | }
71 |
72 | return true;
73 | }
74 |
75 | // Extract color from Shape or Solid color
76 | function getColor(layer) {
77 | try {
78 | if (layer.kind == LayerKind.TEXT) {
79 | return layer.textItem.color.rgb.hexValue;
80 | } else {
81 | var desc = getLayerDescriptor(layer);
82 | var adjs = desc.getList(cTID('Adjs')); // Adjustments
83 |
84 | var clrDesc = adjs.getObjectValue(0),
85 | color = clrDesc.getObjectValue(cTID('Clr '));
86 |
87 | var red = Math.round(color.getDouble(cTID('Rd '))),
88 | green = Math.round(color.getDouble(cTID('Grn '))),
89 | blue = Math.round(color.getDouble(cTID('Bl ')));
90 |
91 | var rgbColor = setRGBColor(red, green, blue);
92 |
93 | return rgbColor.rgb.hexValue;
94 | }
95 | } catch (e) {
96 | return ''; // Adjustments is undefined
97 | }
98 | }
99 |
100 | function getLayerDescriptor(layer) {
101 | var prev = activeDocument.activeLayer;
102 |
103 | if (layer != prev) {
104 | try {
105 | activeDocument.activeLayer = layer;
106 | } catch (e) {}
107 | }
108 |
109 | var ref = new ActionReference();
110 | ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID('Trgt'));
111 | var desc = executeActionGet(ref);
112 |
113 | activeDocument.activeLayer = prev;
114 |
115 | return desc;
116 | }
117 |
118 | // Generate solid RGB color
119 | function setRGBColor(r, g, b) {
120 | var rgb = new RGBColor();
121 |
122 | if (r instanceof Array) {
123 | r = r[0];
124 | g = r[1];
125 | b = r[2];
126 | }
127 |
128 | rgb.red = parseInt(r);
129 | rgb.green = parseInt(g);
130 | rgb.blue = parseInt(b);
131 |
132 | var sColor = new SolidColor();
133 | sColor.rgb = rgb;
134 |
135 | return sColor;
136 | }
137 |
138 | // Search layer color matches
139 | function search(sample, inclSolid) {
140 | var layers = getLayers(activeDocument.layers),
141 | out = []; // Array of layer ID's
142 |
143 | forEach(layers, function (e) {
144 | var color = getColor(e);
145 |
146 | if (color == '') return; // The layer is not a shape or a solid color
147 | if (getLayerType(e) == 11 && !inclSolid) return; // Skip solid
148 |
149 | // Compare hex value
150 | if (color === sample) out.push(e.id);
151 | });
152 |
153 | return out;
154 | }
155 |
156 | // Get all single layers
157 | function getLayers(collection) {
158 | var out = [];
159 |
160 | forEach(collection, function(e) {
161 | if (!e.visible) return;
162 | if (/art/i.test(e.typename)) { // ArtLayer
163 | out.push(e);
164 | } else if (/set/i.test(e.typename)) { // LayerSet
165 | out = [].concat(out, getLayers(e.layers));
166 | } else {
167 | out = [].concat(out, getLayers(e.layers));
168 | }
169 | });
170 |
171 | return out;
172 | }
173 |
174 | // Get LayerKind code
175 | function getLayerType(layer) {
176 | var prev = activeDocument.activeLayer;
177 |
178 | if (layer != prev) {
179 | try {
180 | activeDocument.activeLayer = layer;
181 | } catch (e) {}
182 | }
183 |
184 | var ref = new ActionReference();
185 | var desc = new ActionDescriptor();
186 | ref.putProperty(sTID('property'), sTID('layerKind'));
187 | ref.putEnumerated(sTID('layer'), sTID('ordinal'), sTID('targetEnum'));
188 | var type = executeActionGet(ref).getInteger(sTID('layerKind'));
189 |
190 | activeDocument.activeLayer = prev;
191 |
192 | return type;
193 | }
194 |
195 | // Deselect all layers in the document
196 | function deselect() {
197 | var ref = new ActionReference();
198 | var desc = new ActionDescriptor();
199 | ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID('Trgt') );
200 | desc.putReference(cTID('null'), ref);
201 | executeAction(sTID('selectNoLayers'), desc, DialogModes.NO);
202 | }
203 |
204 | // Select layer by ID
205 | function selectByID(id) {
206 | var ref = new ActionReference();
207 | var desc = new ActionDescriptor();
208 | ref.putIdentifier(cTID('Lyr '), id);
209 | desc.putReference(cTID('null'), ref);
210 | desc.putEnumerated(sTID('selectionModifier'), sTID('selectionModifierType'), sTID('addToSelection'));
211 | desc.putBoolean(cTID('MkVs'), false);
212 | executeAction(cTID('slct'), desc, DialogModes.NO);
213 | }
214 |
215 | // Calls a provided callback function once for each element in an array
216 | function forEach(collection, fn) {
217 | for (var i = 0, cLen = collection.length; i < cLen; i++) {
218 | fn(collection[i]);
219 | }
220 | }
221 |
222 | function cTID(s) {
223 | return app.charIDToTypeID(s);
224 | }
225 |
226 | function sTID(s) {
227 | return app.stringIDToTypeID(s);
228 | }
229 |
230 | try {
231 | main();
232 | } catch(e) {}
--------------------------------------------------------------------------------
/jsx/TIFF2Print.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | TIFF2Print.jsx for Adobe Photoshop
3 | Description: Simple script to save a print ready file in Photoshop.
4 | Features: + Does not change the source file
5 | + Removes guides, empty vector paths before saving TIFF
6 | + Shorten measure units MM > CM > M when possible
7 | + The file name template is configured in the script code
8 | + Allows you to overwrite an existing file or save it with a new index
9 | Date: August, 2018
10 | Author: Sergey Osokin, email: hi@sergosokin.ru
11 |
12 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
13 |
14 | Release notes:
15 | 1.0 Initial version
16 | 1.1 Added ZIP compression.
17 |
18 | Donate (optional):
19 | If you find this script helpful, you can buy me a coffee
20 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
21 | - via Donatty https://donatty.com/sergosokin
22 | - via DonatePay https://new.donatepay.ru/en/@osokin
23 | - via YooMoney https://yoomoney.ru/to/410011149615582
24 |
25 | NOTICE:
26 | Tested with Adobe Photoshop CS5 (Win), CC 2017 & 2018 (Mac), CC 2018 (Win).
27 | This script is provided "as is" without warranty of any kind.
28 | Free to use, not for sale.
29 |
30 | Released under the MIT license.
31 | http://opensource.org/licenses/mit-license.php
32 |
33 | Check my other scripts: https://github.com/creold
34 | */
35 |
36 | //@target photoshop
37 | app.bringToFront();
38 |
39 | // Const
40 | var scriptName = 'TIFF2Print',
41 | scriptVersion = 'v.1.1',
42 | scriptSettings = scriptName + "_settings";
43 |
44 | // Configuration
45 | if (documents.length > 0) {
46 | var originDoc = app.activeDocument,
47 | savePath = '',
48 | saveUnits = app.preferences.rulerUnits, // Save current units
49 | printExt = '.tif', // Extension of a printed file
50 | printSuffix = 'print', // Suffix before print file extension
51 | previewExt = '.jpg', // Extension of a preview file
52 | previewSuffix = 'preview', // Suffix before preview file extension
53 | divider = '-', // For suffix and to replace spaces
54 | sizeSuffix = '', // Linear size suffix
55 | colorProfile = false, //Embed color profile in print file
56 | jpegQuality = 9, // Maximum value: 12
57 | jpgSizeMax = 1200, // Unit: px. Size on the larger side
58 | compressPref; // Declare variables to initialize settings
59 | }
60 |
61 | // Main function
62 | function main() {
63 | if (!isCorrectEnv()) return;
64 | uiDialog().show();
65 | }
66 |
67 | // Check the script environment
68 | function isCorrectEnv() {
69 | var args = ['app', 'document'];
70 |
71 | for (var i = 0; i < args.length; i++) {
72 | switch (args[i].toString().toLowerCase()) {
73 | case 'app':
74 | if (!/photoshop/i.test(app.name)) {
75 | alert('Error\nRun script from Adobe Photoshop');
76 | return false;
77 | }
78 | break;
79 | case 'document':
80 | if (!documents.length) {
81 | alert('Error\nOpen a document and try again');
82 | return false;
83 | }
84 | break;
85 | }
86 | }
87 |
88 | return true;
89 | }
90 |
91 | // Create dialog window
92 | function uiDialog() {
93 | var win = new Window('dialog', scriptName + ' ' + scriptVersion);
94 | win.orientation = 'column';
95 | win.alignChildren = ['fill', 'fill'];
96 |
97 | var namePnl = win.add('panel', undefined, 'Name settings');
98 | namePnl.alignChildren = 'left';
99 | // Add size in file name or not
100 | var isSize = namePnl.add('checkbox', undefined, 'Add width and height (mm)');
101 | isSize.helpTip = 'Sample: ';
401 | html.write(htmlBody);
402 | html.close();
403 | html.execute();
404 | }
405 |
406 | // Run script
407 | try {
408 | main();
409 | } catch (e) {}
--------------------------------------------------------------------------------
/jsx/TextBlock.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | TextBlock.jsx for Adobe Photoshop
3 | Description: Convert selected text layers into a block of text
4 | Date: March, 2025
5 | Modification date: April, 2025
6 | Author: Sergey Osokin, email: hi@sergosokin.ru
7 |
8 | Version for Adobe Illustrator:
9 | https://github.com/creold/illustrator-scripts/blob/master/md/Text.md
10 |
11 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
12 |
13 | Release notes:
14 | 0.2 Added option to center text block and hide/remove original layers
15 | 0.1 Initial version
16 |
17 | Donate (optional):
18 | If you find this script helpful, you can buy me a coffee
19 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
20 | - via Donatty https://donatty.com/sergosokin
21 | - via DonatePay https://new.donatepay.ru/en/@osokin
22 | - via YooMoney https://yoomoney.ru/to/410011149615582
23 |
24 | NOTICE:
25 | Tested with Adobe Photoshop CC 2019-2024 (Mac/Win).
26 | This script is provided "as is" without warranty of any kind.
27 | Free to use, not for sale
28 |
29 | Released under the MIT license
30 | http://opensource.org/licenses/mit-license.php
31 |
32 | Check my other scripts: https://github.com/creold
33 | */
34 |
35 | //@target photoshop
36 | app.bringToFront();
37 |
38 | function main() {
39 | var SCRIPT = {
40 | name: 'Text Block',
41 | version: 'v0.2'
42 | };
43 |
44 | var CFG = {
45 | width: '300 px', // Text Block width
46 | spacing: '10 px', // Text lines spacing
47 | units: app.preferences.rulerUnits,
48 | isMac: /mac/i.test($.os),
49 | settings: 'TB_settings',
50 | };
51 |
52 | if (!isCorrectEnv()) return;
53 | var doc = app.activeDocument;
54 | var idx = getSelectedLayersIdx();
55 |
56 | var texts = getTextLayers(doc.layers, idx);
57 | if (texts.length < 2) {
58 | alert('Texts not found\nPlease select at least two text layers and try again', 'Script error');
59 | return;
60 | }
61 |
62 | // Sort array by Y and X positions
63 | sortByPosition(texts, 10);
64 |
65 | // DIALOG
66 | var win = new Window('dialog', SCRIPT.name + ' ' + SCRIPT.version);
67 | win.alignChildren = ['fill', 'top'];
68 |
69 | // INPUTS
70 | var settPnl = win.add('panel', undefined, 'Block Settings');
71 | settPnl.alignChildren = ['fill', 'top'];
72 | settPnl.margins = [10, 15, 5, 15];
73 |
74 | var wrapper1 = settPnl.add('group');
75 | wrapper1.alignChildren = ['left', 'center'];
76 |
77 | var wLbl = wrapper1.add('statictext', undefined, 'Width:');
78 | wLbl.preferredSize.width = 55;
79 |
80 | var wInp = wrapper1.add('edittext', undefined, CFG.width);
81 | wInp.preferredSize.width = 80;
82 | wInp.helpTip = 'Supporterd units:\npx, pt, in, mm, cm, m, ft, yd';
83 | wInp.active = true;
84 |
85 | var wrapper2 = settPnl.add('group');
86 | wrapper2.alignChildren = ['left', 'center'];
87 |
88 | var spLbl = wrapper2.add('statictext', undefined, 'Spacing:');
89 | spLbl.preferredSize.width = 55;
90 |
91 | var spInp = wrapper2.add('edittext', undefined, CFG.spacing);
92 | spInp.preferredSize.width = 80;
93 | spInp.helpTip = 'Supporterd units:\npx, pt, in, mm, cm, m, ft, yd';
94 |
95 | var isToCenter = settPnl.add('checkbox', undefined, 'Center To Canvas');
96 |
97 | // ORIGINAL LAYERS POST-PROCESS
98 | var origPnl = win.add('panel', undefined, 'Original Texts');
99 | origPnl.alignChildren = ['fill', 'top'];
100 | origPnl.margins = [10, 15, 5, 15];
101 |
102 | var isKeep = origPnl.add('radiobutton', undefined, 'Keep');
103 | isKeep.value = true;
104 | var isHide = origPnl.add('radiobutton', undefined, 'Hide');
105 | var isRemove = origPnl.add('radiobutton', undefined, 'Remove');
106 |
107 | // BUTTONS
108 | var btns = win.add('group');
109 | btns.alignChildren = ['fill', 'center'];
110 | btns.spacing = 10;
111 |
112 | var cancel, ok;
113 | if (CFG.isMac) {
114 | cancel = btns.add('button', undefined, 'Cancel', { name: 'cancel' });
115 | ok = btns.add('button', undefined, 'OK', { name: 'ok' });
116 | } else {
117 | ok = btns.add('button', undefined, 'OK', { name: 'ok' });
118 | cancel = btns.add('button', undefined, 'Cancel', { name: 'cancel' });
119 | }
120 |
121 | cancel.helpTip = 'Press Esc to Close';
122 | ok.helpTip = 'Press Enter to Run';
123 |
124 | var copyright = win.add('statictext', undefined, 'Click Here To Visit Github');
125 | copyright.justify = 'center';
126 |
127 | // EVENTS
128 | loadSettings();
129 |
130 | wInp.onChange = spInp.onChange = function () {
131 | var units = parseUnits(this.text, 'px');
132 | var num = strToNum(this.text, CFG.width);
133 | this.text = num + ' ' + units;
134 | }
135 |
136 | /**
137 | * Use Up / Down arrow keys (+ Shift) to change value
138 | */
139 | bindStepperKeys(wInp, 0.1, 100000);
140 | bindStepperKeys(spInp, 0, 100000);
141 |
142 | cancel.onClick = win.close;
143 |
144 | ok.onClick = function () {
145 | doc.suspendHistory('TextBlock Script', 'okClick()');
146 | }
147 |
148 | copyright.addEventListener('mousedown', function () {
149 | openURL('https://github.com/creold');
150 | });
151 |
152 | function okClick() {
153 | saveSettings();
154 |
155 | app.preferences.rulerUnits = Units.PIXELS;
156 |
157 | var wUnits = parseUnits(wInp.text, 'px');
158 | var blockWidth = convertUnits( strToNum(wInp.text, CFG.width), wUnits, 'px' );
159 |
160 | var spUnits = parseUnits(spInp.text, 'px');
161 | var blockSpacing = convertUnits( strToNum(spInp.text, CFG.spacing), spUnits, 'px' );
162 |
163 | // Add a group to final output
164 | var textGroup = doc.layerSets.add();
165 | textGroup.name = 'Text Block';
166 |
167 | var nextTop = 0;
168 | var posLeft = texts[0].bounds[0];
169 | var posRight = texts[0].bounds[2];
170 | var posTop = texts[0].bounds[1];
171 |
172 | // Create text block
173 | for (var i = 0; i < texts.length; i++) {
174 | var currText = texts[i];
175 | var dupText = currText.duplicate(textGroup, ElementPlacement.PLACEATEND);
176 | dupText.name = currText.name;
177 |
178 | var bounds = dupText.bounds;
179 | var currWidth = bounds[2].value - bounds[0].value;
180 | var ratio = (blockWidth / currWidth) * 100;
181 |
182 | dupText.resize(ratio, ratio, AnchorPosition.TOPLEFT);
183 |
184 | bounds = dupText.bounds;
185 | var deltaX = bounds[0].value;
186 | var deltaY = bounds[1].value;
187 |
188 | dupText.translate(-deltaX, -deltaY + nextTop + blockSpacing);
189 | nextTop += bounds[3].value - bounds[1].value + blockSpacing;
190 | }
191 |
192 | // Align text block
193 | if (isToCenter.value) {
194 | alignToCenter(doc, textGroup);
195 | } else if (!isKeep.value) {
196 | textGroup.translate(posLeft, posTop);
197 | } else {
198 | textGroup.translate(posRight, posTop);
199 | }
200 |
201 | // Original layers
202 | for(var j = texts.length - 1; j >= 0; j--){
203 | if (isHide.value) {
204 | texts[j].visible = false;
205 | } else if (isRemove.value) {
206 | texts[j].remove();
207 | }
208 | }
209 |
210 | app.preferences.rulerUnits = CFG.units;
211 |
212 | win.close();
213 | }
214 |
215 | /**
216 | * Handle keyboard input to shift numerical values
217 | * @param {Object} input - The input element to which the event listener will be attached
218 | * @param {number} min - The minimum allowed value for the numerical input
219 | * @param {number} max - The maximum allowed value for the numerical input
220 | * @returns {void}
221 | */
222 | function bindStepperKeys(input, min, max) {
223 | input.addEventListener('keydown', function (kd) {
224 | var step = ScriptUI.environment.keyboardState['shiftKey'] ? 10 : 1;
225 | var units = parseUnits(this.text, 'pt');
226 | var num = parseFloat(this.text);
227 | if (kd.keyName == 'Down' || kd.keyName == 'LeftBracket') {
228 | this.text = (min && (num - step) < min) ? min : num - step;
229 | this.text += ' ' + units;
230 | kd.preventDefault();
231 | }
232 | if (kd.keyName == 'Up' || kd.keyName == 'RightBracket') {
233 | this.text = (max && (num + step) > max) ? max : num + step;
234 | this.text += ' ' + units;
235 | kd.preventDefault();
236 | }
237 | });
238 | }
239 |
240 | /**
241 | * Save UI options in Photoshop preferences
242 | */
243 | function saveSettings() {
244 | var desc = new ActionDescriptor();
245 | desc.putString(0, wInp.text);
246 | desc.putString(1, spInp.text);
247 | desc.putBoolean(2, isToCenter.value);
248 | desc.putBoolean(3, isKeep.value);
249 | desc.putBoolean(4, isHide.value);
250 | desc.putBoolean(5, isRemove.value);
251 | app.putCustomOptions(CFG.settings, desc, true);
252 | }
253 |
254 | /**
255 | * Load options from Photoshop preferences
256 | */
257 | function loadSettings() {
258 | try {
259 | var desc = app.getCustomOptions(CFG.settings);
260 | } catch (err) {}
261 | if (typeof desc != 'undefined') {
262 | try {
263 | wInp.text = desc.getString(0);
264 | spInp.text = desc.getString(1);
265 | isToCenter.value = desc.getBoolean(2);
266 | isKeep.value = desc.getBoolean(3);
267 | isHide.value = desc.getBoolean(4);
268 | isRemove.value = desc.getBoolean(5);
269 | return;
270 | } catch (err) {}
271 | }
272 | }
273 |
274 | win.center();
275 | win.show();
276 | }
277 |
278 | /**
279 | * Checks if the script is running in the correct environment
280 | *
281 | * @returns {boolean} - Returns `true` if the environment is correct
282 | */
283 | function isCorrectEnv() {
284 | var args = ['app', 'document'];
285 |
286 | for (var i = 0; i < args.length; i++) {
287 | switch (args[i].toString().toLowerCase()) {
288 | case 'app':
289 | if (!/photoshop/i.test(app.name)) {
290 | alert('Wrong application\nRun script from Adobe Photoshop', 'Script error');
291 | return false;
292 | }
293 | break;
294 | case 'document':
295 | if (!documents.length) {
296 | alert('No documents\nOpen a document and try again', 'Script error');
297 | return false;
298 | }
299 | break;
300 | }
301 | }
302 |
303 | return true;
304 | }
305 |
306 | /**
307 | * Get the indexes of all selected layers in the active Photoshop document
308 | * https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-find-selected-layers-and-run-events/td-p/10269273 by Geppetto Luis
309 | *
310 | * @returns {Array} - An array containing the indexes of the selected layers
311 | */
312 | function getSelectedLayersIdx() {
313 | var results = new Array;
314 | var ref = new ActionReference();
315 | ref.putEnumerated(cTID('Dcmn'), cTID('Ordn'), cTID('Trgt'));
316 | var desc = executeActionGet(ref);
317 |
318 | if (desc.hasKey(sTID('targetLayers'))) {
319 | desc = desc.getList(sTID('targetLayers'));
320 | var counter = desc.count;
321 | var results = new Array();
322 | for (var i = 0; i < counter; i++) {
323 | try {
324 | activeDocument.backgroundLayer;
325 | results.push(desc.getReference(i).getIndex());
326 | } catch (err) {
327 | results.push(desc.getReference(i).getIndex() + 1);
328 | }
329 | }
330 | } else {
331 | var ref = new ActionReference();
332 | ref.putProperty(cTID('Prpr'), cTID('ItmI'));
333 | ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID('Trgt'));
334 | try {
335 | activeDocument.backgroundLayer;
336 | results.push(executeActionGet(ref).getInteger(cTID('ItmI')) - 1);
337 | } catch (err) {
338 | results.push(executeActionGet(ref).getInteger(cTID('ItmI')));
339 | }
340 | }
341 |
342 | return results;
343 | }
344 |
345 | /**
346 | * Convert a string identifier to a character identifier
347 | *
348 | * @param {string} s - The string identifier
349 | * @returns {number} - The corresponding character identifier
350 | */
351 | function cTID(s) {
352 | return app.charIDToTypeID(s);
353 | }
354 |
355 | /**
356 | * Convert a string identifier to a type identifier
357 | *
358 | * @param {string} s - The string identifier
359 | * @returns {number} - The corresponding type identifier
360 | */
361 | function sTID(s) {
362 | return app.stringIDToTypeID(s);
363 | }
364 |
365 | /**
366 | * Get all text layers from the given layers array that match the provided indexes
367 | *
368 | * @param {[Object|Array]} layers - The layers array to search
369 | * @param {number[]} idx - The array of indexes to match
370 | * @returns {Array} - An array containing the text layers matching the provided indexes
371 | */
372 | function getTextLayers(layers, idx) {
373 | var results = [];
374 |
375 | for (var i = 0; i < layers.length; i++) {
376 | var lyr = layers[i];
377 | if (lyr.kind === LayerKind.TEXT) {
378 | for (var j = 0; j < idx.length; j++) {
379 | try {
380 | activeDocument.backgroundLayer;
381 | if (lyr.itemIndex - 1 === idx[j]) {
382 | results.push(lyr);
383 | break;
384 | }
385 | } catch (err) {
386 | if (lyr.itemIndex === idx[j]) {
387 | results.push(lyr);
388 | break;
389 | }
390 | }
391 | }
392 | } else if (lyr.typename === 'LayerSet') {
393 | results = [].concat(results, getTextLayers(lyr.layers, idx));
394 | }
395 | }
396 |
397 | return results;
398 | }
399 |
400 | /**
401 | * Sort items based on their position
402 | *
403 | * @param {(Object|Array)} coll - Collection to be sorted
404 | * @param {number} tolerance - The tolerance within which objects are considered to have the same top position
405 | */
406 | function sortByPosition(coll, tolerance) {
407 | if (arguments.length == 1 || tolerance == undefined) {
408 | tolerance = 10;
409 | }
410 |
411 | coll.sort(function(a, b) {
412 | var boundsA = a.bounds;
413 | var boundsB = b.bounds;
414 |
415 | var yA = boundsA[1].value;
416 | var yB = boundsB[1].value;
417 |
418 | if (Math.abs(yA - yB) > tolerance) {
419 | return yA - yB;
420 | }
421 |
422 | var xA = boundsA[0].value;
423 | var xB = boundsB[0].value;
424 |
425 | if (Math.abs(xA - xB) > tolerance) {
426 | return xA - xB;
427 | }
428 |
429 | return 0;
430 | });
431 | }
432 |
433 | /**
434 | * Parse units from a mixed string
435 | *
436 | * @param {string} str - The input string containing the numeric value and units (e.g., '10px').
437 | * @param {string} def - The default units to be returned if no units are found in the input string
438 | * @returns {string} - The parsed units or the default units if not found
439 | */
440 | function parseUnits(str, def) {
441 | var match = str.match(/(\d+(\.\d+)?)\s*([a-zA-Z]+)\s*[^a-zA-Z]*$/);
442 |
443 | if (match) {
444 | var units = match[3].toLowerCase();
445 | var validUnits = ['px', 'pt', 'in', 'mm', 'cm', 'm', 'ft', 'yd'];
446 |
447 | for (var i = 0; i < validUnits.length; i++) {
448 | if (units === validUnits[i]) return units;
449 | }
450 | }
451 |
452 | return def;
453 | }
454 |
455 | /**
456 | * Convert a value from one set of units to another
457 | *
458 | * @param {string} value - The numeric value to be converted
459 | * @param {string} currUnits - The current units of the value (e.g., 'in', 'mm', 'pt')
460 | * @param {string} newUnits - The desired units for the converted value (e.g., 'in', 'mm', 'pt')
461 | * @returns {number} - The converted value in the specified units
462 | */
463 | function convertUnits(value, currUnits, newUnits) {
464 | return UnitValue(value, currUnits).as(newUnits);
465 | }
466 |
467 | /**
468 | * Convert string to absolute number
469 | *
470 | * @param {string} str - The string to convert to a number
471 | * @param {number} def - The default value to return if the conversion fails
472 | * @returns {number} - The converted number
473 | */
474 | function strToNum(str, def) {
475 | if (arguments.length == 1 || def == undefined) def = 1;
476 | str = str.replace(/,/g, '.').replace(/[^\d.]/g, '');
477 | str = str.split('.');
478 | str = str[0] ? str[0] + '.' + str.slice(1).join('') : '';
479 | if (isNaN(str) || !str.length) return parseFloat(def);
480 | else return parseFloat(str);
481 | }
482 |
483 | /**
484 | * Center an item within the document canvas
485 | *
486 | * @param {Object} doc - The Photoshop document
487 | * @param {Object} item - The layer or group to be centered
488 | * @returns {void}
489 | */
490 | function alignToCenter(doc, item) {
491 | var bnds = item.bounds;
492 | var width = bnds[2] - bnds[0];
493 | var height = bnds[3] - bnds[1];
494 |
495 | var docCenterX = doc.width / 2;
496 | var docCenterY = doc.height / 2;
497 |
498 | var currCenterX = bnds[0] + width / 2;
499 | var currCenterY = bnds[1] + height / 2;
500 |
501 | var offsetX = docCenterX - currCenterX;
502 | var offsetY = docCenterY - currCenterY;
503 |
504 | item.translate(offsetX, offsetY);
505 | }
506 |
507 | /**
508 | * Open a URL in the default web browser
509 | *
510 | * @param {string} url - The URL to open in the web browser
511 | * @returns {void}
512 | */
513 | function openURL(url) {
514 | var html = new File(Folder.temp.absoluteURI + '/aisLink.html');
515 | html.open('w');
516 | var htmlBody = ' ';
517 | html.write(htmlBody);
518 | html.close();
519 | html.execute();
520 | }
521 |
522 | try {
523 | main();
524 | } catch(err) {}
--------------------------------------------------------------------------------
/jsx/ToggleLayersLocksByName.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | ToggleLayersLocksByName.jsx for Adobe Photoshop
3 | Description: Locks layers in the document based on the keyword in the name
4 | Date: September, 2021
5 | Author: Sergey Osokin, email: hi@sergosokin.ru
6 |
7 | Installation: https://github.com/creold/photoshop-scripts#how-to-run-scripts
8 |
9 | Donate (optional):
10 | If you find this script helpful, you can buy me a coffee
11 | - via Buymeacoffee: https://www.buymeacoffee.com/aiscripts
12 | - via Donatty https://donatty.com/sergosokin
13 | - via DonatePay https://new.donatepay.ru/en/@osokin
14 | - via YooMoney https://yoomoney.ru/to/410011149615582
15 |
16 | NOTICE:
17 | Tested with Adobe Photoshop CC 2019.
18 | This script is provided "as is" without warranty of any kind.
19 | Free to use, not for sale
20 |
21 | Released under the MIT license
22 | http://opensource.org/licenses/mit-license.php
23 |
24 | Check my other scripts: https://github.com/creold
25 | */
26 |
27 | //@target photoshop
28 |
29 | function main() {
30 | if (!isCorrectEnv()) return;
31 |
32 | var doc = app.activeDocument,
33 | key = '[lock]',
34 | allLayers = [];
35 |
36 | allLayers = collectAllLayers(doc, allLayers);
37 |
38 | for (var i = 0, len = allLayers.length; i < len; i++) {
39 | var lyr = allLayers[i];
40 | if (!lyr.isBackgroundLayer && lyr.name.indexOf(key) !== -1) {
41 | lyr.allLocked = !lyr.allLocked;
42 | }
43 | }
44 | }
45 |
46 | // Check the script environment
47 | function isCorrectEnv() {
48 | var args = ['app', 'document'];
49 |
50 | for (var i = 0; i < args.length; i++) {
51 | switch (args[i].toString().toLowerCase()) {
52 | case 'app':
53 | if (!/photoshop/i.test(app.name)) {
54 | alert('Error\nRun script from Adobe Photoshop');
55 | return false;
56 | }
57 | break;
58 | case 'document':
59 | if (!documents.length) {
60 | alert('Error\nOpen a document and try again');
61 | return false;
62 | }
63 | break;
64 | }
65 | }
66 |
67 | return true;
68 | }
69 |
70 | function collectAllLayers(doc, allLayers) {
71 | for (var i = 0; i < doc.layers.length; i++) {
72 | var lyr = doc.layers[i];
73 | if (lyr.typename === 'ArtLayer') {
74 | allLayers.push(lyr);
75 | } else if (lyr.typename === 'LayerSet') {
76 | allLayers.push(lyr);
77 | collectAllLayers(lyr, allLayers);
78 | } else {
79 | collectAllLayers(lyr, allLayers);
80 | }
81 | }
82 |
83 | return allLayers;
84 | }
85 |
86 | try {
87 | main();
88 | } catch (e) {}
--------------------------------------------------------------------------------