Easy Automation and Scripting in Photoshop (Patreon)
Videos
-
clip01.mp4
Downloads
Content
Although it’s perhaps not as well-known as you might think, Photoshop (and all Adobe apps) have extensive support for scripting and plugin development. I’m big fan of using automation to be more productive, so I was eager to script a lot of my most common Photoshop tasks. This article will take a quick look at the general syntax for Adobe script development, using three scripts I wrote as examples.
For a long time Adobe only supported a very outdated version of JavaScript via their ExtendScript framework. That has been phased out in favor of UXP (Unified Extensibility Platform). UXP is based on modern JavaScript and is very robust and easy to use.
We’ll be focusing on Photoshop here, but UXP is available for all Adobe apps. I can imagine that it would be very useful in After Effects in particular.
All the scripts discussed here are available on GitHub: https://github.com/BrianHanke/PhotoshopScripts
Now, without any further ado, let’s dig in!
Writing Scripts with UXP
In general, Photoshop scripts take the form of:
Module import
Function declaration
Function call
This means we import the Photoshop/UXP modules we need, we declare a function (or functions) that perform the tasks we want, then we call said function(s) in Photoshop when the user runs the script.
Let’s see how this all plays out in this short script that closes all open documents without saving, CloseAll.psjs.
The first line imports the app and core Photoshop modules:
const { app, core } = require('photoshop');
Next is a closeAllWithoutSaving function that accesses the Photoshop API to close all open documents.
async function closeAllWithoutSaving() { await core.executeAsModal(async () => { const docs = app.documents;
for (let i = docs.length - 1; i >= 0; i--) { try { await docs[i].close(saveOptions = "checkNo"); } catch (e) { console.log("Could not close document " + i); } } }, { "commandName": "Close All Without Saving" });}
Note the core.executeAsModal await function call. One great feature of UXP is that it’s non-blocking and doesn’t freeze the Photoshop UI. It’s not multithreaded in the sense of being able to run our code on separate threads, but it does make sure the PS interface remains responsive.
The contents of the function are simple: access the list of open documents using app.documents, then loop through them from last to first, closing each one in order and disabling the save prompt via saveOptions = “checkNo”.
The commandName section gives the function an identifier for history/logs.
Finally, the last line of the script calls our function:
closeAllWithoutSaving();
That’s it! To run this in PS, go to File > Scripts > Browse and load the .psjs file from disk. You can also record an Action that does this in one step. (Actions in Photoshop are recordings of your interactions within PS for a period of time.)
Another simple script I wrote is Paste from Clipboard. This makes a new document from whatever image is occupying the clipboard (for example, via the Print Screen key).
const { app, core, action } = require('photoshop');
async function newFromClipboard() { await core.executeAsModal(async () => { try { await app.createDocument({ preset: "Clipboard" }); await action.batchPlay([{ "_obj": "paste" }], {}); } catch (e) { console.error("Paste failed: ", e); } }, { "commandName": "New from Clipboard" });}
newFromClipboard();
This follows our familiar format: load modules, declare function, await, perform a task or two, then call the function.
One thing that stands out here is the action.batchPlay syntax. This lets us access the low-level Photoshop “paste” command. In this case it’s fairly simple, but batchPlay can get complicated when accessing more and more functions, tools, and options.
Lastly, head on over the GitHub and check out the most complicated script of the bunch, Export Incremental JPG: https://github.com/BrianHanke/PhotoshopScripts/blob/main/scripts/JpgExport.psjs
This script showcases the ability of UXP to interact with the computer’s file system.
I wanted to export images using auto-incremented names: pic01, pic02, pic03, etc. The script looks either at the top layer for a numeric value (giving the user manual control) or it scans the output folder and increments the last number of the existing sequence. If pic01 and pic02 are there, it will save the current document as pic03.
This is a huge timesaver and makes great use of some JavaScript quality of life features like setting the padding of numbers and converting numbers to and from strings.
Final Thoughts
UXP is a wonderful framework for automation in Photoshop (and beyond) and it’s easy to use since it’s based on standard JavaScript.
Probably the main sticking point for new developers is knowing the “magic words” for executing built-in Photoshop commands. The batchPlay/_obj/paste syntax isn’t too terrible since “paste” is just the name of the command in Photoshop’s UI, but it gets much, much worse. The best approach is to refer to Adobe’s extensive documentation. It includes a full API reference, plus lot of samples and demo files: https://developer.adobe.com/photoshop/uxp/2022/
Enjoy your Adobe scripting journey!