Scripting CC Apps Using CEP Panels
--
Our guest developer post this week is by Davide Barranca, a Photoshop retoucher and developer based in Italy.
Update 4/10/2018: Our CEP Getting Started resources are now on GitHub! See our repo for the latest information.
This post is for beginning developers who have built a panel, or are just starting to build panels, and would like to understand how CEP communicates with CC host applications like Photoshop, InDesign, and so forth. (If you’ve never built a panel, check out our first post: “How to create your first Adobe panel in 6 easy steps”).
— Erin Finnegan, Community Engineer, Adobe
In this post we’ll start looking at the basic mechanisms with which HTML Panels communicate with their host application: namely, how to run scripts.
How it works
In a nutshell, you can think of HTML panels as web applications running within the context of Adobe Creative Cloud apps. The stack of technologies that makes this possible is known as CEP (Common Extensibility Platform), and can be illustrated this way:
A panel is literally made of a browser instance (Chromium Embedded Framework) that provides the environment to run HTML/CSS/JS code. The whole thing wouldn’t be very exciting per se, except that CEP makes a communication channel available between the host application (Photoshop, InDesign, Illustrator, etc.) and the panel itself. As a result, the panel can do all the wonders web applications usually do, plus it can drive the host application, and get information from the host app, via scripting.
There’s no shared language, though: while panels are fluent with modern JavaScript (JS), they cannot make any direct use of ExtendScript (JSX), the scripting language Photoshop and Creative Cloud apps deal with, even if the two share a common ancestor (a language specification). The process of interpreting code must involve two separate engines: the panel’s (JS), and the host app’s (JSX).
So, how does this communication go on? The panel/JS side can send strings of ExtendScript code to the host app/JSX side, and then wait for the host app/JSX side to run it and return the result (if any). It’s like the panel saying “Hi Photoshop, I have no idea what this ‘app.activeDocument.layers.length’
thing could possibly mean, can you please give it a run?”. And Photoshop, obligingly replies “15. You’re welcome”. This is the simplest scenario; you could make it event-based, but that would be a different blog post.
Let’s look at some examples now. I will use Photoshop because it’s what I’m mostly familiar with, but think about the Adobe application of your choice and it will work the very same.
Communicating from the panel to the host application
Everything is based on the CSInterface
class (provided by the CSInterface.js
file you can find in Adobe's GitHub repository), that you must instantiate first in the panel's JS code:
Then, you can send messages from JS to JSX (i.e. from the panel to the host application) using the evalScript()
method:
This is as simple as it gets. From the panel, you’re telling the Adobe host application (like Photoshop): “please Photoshop, run alert("Hello World!")
, can you?". And no doubts Photoshop will obligingly do so.
More meaningful communications may include proper function calls, such as the following example — let’s pretend we’ve developed, say, a new sharpening routine for web-targeted JPGs:
Here, from the panel’s JS, you’re sending this intriguing 'addSharpeningForWeb()'
string to Photoshop, but what is Photoshop supposed to do? An HTML panel stores its own ExtendScript code in one (or more) .jsx
file(s) – the main one being defined in the CSXS/manifest.xml
, within the <ScriptPath>
tag.
In that hostscript.jsx
file will sit the actual code for that very function:
What if you need to pass data to these functions? Say that the web sharpening function needs to know the strength of the sharpening — a numeric parameter that the user sets in the panel itself with a slider. How do you hand this parameter, along with the function call string, to the JSX engine?
By means of string interpolation, you can easily insert the parameter between the two parenthesis. You can also use the new ES2015 template strings to interpolate variables instead (see the Adobe I/O blog post on string templates for examples). Just in case, I suggest you to test your code for proper backward compatibility: each host app version (say, Photoshop CC 2018 vs. CC 2017 vs. CC 2015.5) implements a different Chromium Embedded Framework, and your code may break on older versions.
Did this post enrich your understanding of CEP? Let us know in the comments. There’s definitely more to learn around this topic, so keep checking on Adobe I/O for the next blog post!
Davide Barranca is the author of two books about panels, Adobe Photoshop HTML Panels Development and The Ultimate Guide on Native Installers and Automated Build Systems. He blogs about panels and script development on his homepage, davidebarranca.com.
For more stories like this, subscribe to our Creative Cloud Developer Newsletter.