Created

1 July 2014

Requirements

Prerequisite knowledge

This article assumes basic familiarity with Creative Suite and Creative Cloud product extensibility.

User level

All

In 2013 Adobe introduced a new way to extend and customize many of its products. Up until then, you had the option to use C++, ExtendScript or ActionScript to code your extensions. You could also mix and match, the result of which we call a hybrid extension. This was a great way to extend and customize many of the most popular Adobe products. When Adobe Creative Cloud was launched in June 2013, Photoshop and Premiere Pro included a new option, HTML5. You code in JavaScript and use familiar JavaScript frameworks, well known to web developers, to extend Adobe products. HTML and CSS is used to lay out the UI. Now, Photoshop, InDesign, Illustrator, Flash Pro, Premiere Pro and Prelude all support HTML5 extensions.

Update: With Creative Cloud 2014, you can use Node.js using CEP 5.

Why should I care?

With HTML5 support for extensions, you have all the tools of web development at your disposal. If you are a web developer, you already know how to make extensions.

Using HTML5 to build extensions and plugins opens up immense opportunities to rapidly build features for Adobe products. Even Adobe itself has used CEP to build some of its core features. For example, the Share on Behance plugin in Photoshop and Illustrator is built using CEP and HTML5. Another example is the Kuler panel in Flash Professional CC.

The platform underlying the new extensions is called the Common Extensibility Platform (CEP). It was previously known as CSXS. In fact, in supported Adobe products today, CEP hosts both the Flash and HTML5 extension engines. However, that is about to change.

Step by step, product update by product update, Flash extensibility will disappear from Adobe’s products.

APIs

Update: With the Adobe Creative Cloud 2014 products, you can use Node and NPMs in addition to the CEP APIs. Learn more

CEP provides three JavaScript APIs — most developers are only aware of two of them, Vulcan and CSInterface. You can check out Extension Builder 3 to read about the CSInterface and Vulcan JavaScript APIs. In this article, I’m going to talk about the third API, CEPEngine_extensions. It is actually a JavaScript interface to a CEF extension. (CEF stands for Chromium Embedded Framework).

CEF is the engine driving the extension. You can think of it as a browser running within an Adobe product.

CEF has been used to build a few well known client (desktop) applications. Spotify, Evernote, Adobe Brackets (and Edge Code), Adobe Edge Animate and Edge Inspect are among well known desktop applications that make use of CEF. (You can find a longer list in CEF’s Wikipedia article.)

CEPEngine_extensions

CEPEngine_extensions provides an API for three main purposes:

  1. File I/O: Manipulation of files and folders
  2. Process Control: Manipulation of external processes
  3. Base64 encoding/decoding: Encode data and text to/from Base64

Note: Refer to the Adobe CC Extension SDK documentation for a full reference.

You do not need to include any JavaScript file in your extension project. It will “just work”.

Every function returns an object with the property err. If the function returns a value, it returns an object with two properties, data and err.

The data property contains the result of the operation, if no errors were encountered. err contains the error code, or 0 if there is no error.

You can use this to quickly capture if the operation is successful. Like this:

if (result.err==0){ //Success. Do something clever. } else { // handle error }

/bin/ls is very probably not what you want to execute; I’ve just used it as an example. You can run something more useful, like a Java .jar file or an command line ftp client to upload your assets to a ftp repository. The sky’s the limit.

GetWorkingDirectory() Retrieves the working directory of an extension process.

Example:

var path = ‘/bin/ls’; var result = window.cep.process.createProcess(path); var wDir = window.cep.process.getWorkingDirectory(result.data); alert('Working directory of PID: ' + result.data + ' is ' + wDir.data); //result Working directory of PID: 22323 is /bin

IsRunning() Reports whether an extension process is currently running.

Example:

var result = window.cep.process.createProcess(“/bin/ls”); if (result.err == 0) { //no error var pid = result.data; //get process ID isRunning = window.cep.process.isRunning(pid); if (true == isRunning.data){ // do something clever } }

Other related API calls that work the same way:

Terminate() Terminates an extension process.
WaitFor() Waits for an extension process to quit.
WriteStdIn() Writes data to the standard input of an extension

Refer to the Adobe CC Extension SDK documentation for a full reference.

Functions with callback handlers

Using callback handlers is a great way to handle an event. In this case, the event is the output (data or error) of a process. Instead of waiting for the event and blocking the panel, the panel registers the callback handler and then goes on run other code. When the event occurs, the callback handler is run asynchronously. This article explains it in simple terms.

OnQuit() Registers an on-quit callback handler method for a process.

Example:

var result = window.cep.process.createProcess(‘/bin/mkdir’,’/tmp/testOnQuit'); window.cep.process.onquit(result.data,function(){ alert(‘callback called’); //onquit was called as soon as mkdir quit });

A just-a-little-bit more elaborate example:

function callBackTest(){ //create folder /tmp var result = window.cep.process.createProcess(‘/bin/mkdir’,’/tmp'); //zip a file window.cep.process.onquit(result.data,function(){ window.cep.process.createProcess(‘/usr/bin/zip’, ‘/tmp/output.zip’,’/myfolder/input.zip’); alert(‘Zip completed after callback. PID was ‘+ result.data); }); }

Other similar API calls:

RegisterExtensionUnloadCallback() Registers a callback function for extension unload.
SetupStdErrHandler() Registers up a standard-error handler for an extension process.
SetupStdOutHandler() Registers a standard-output handler for an extension process.

File I/O

This part of the API is pretty self explanatory. I’ll highlight just two functions:

ShowOpenDialog() Displays a File Open dialog which is platform specific.

Example:

var filetypes = new Array(); filetypes[0] = “pptx”; filetypes[1] = “do”; filetypes[2] = “psd”; var result = window.cep.fs.showOpenDialog(false,false,’SELECT PSD’,’/tmp/’,filetypes); alert(result.data); //displays the path to the selected file

readFile() Reads a file from the local file system

Example:

var path = “/tmp/”; var result = window.cep.fs.readFile(path); if (result.err == 0) { //success alert(result.data); // displays file content } else { …// handle failure }

Other similar API calls:

IsDirectory() Reports whether an item in the file system is a file or folder.
MakeDir() Creates a new folder

ReadDir() Reads the contents of a folder.
Rename() Renames a file or folder.

SetPosixPermissions() Sets permissions for a file or folder
WriteFile() Writes data to a file, replacing the file if it already exists.
DeleteFileOrDirectory() Deletes a file or folder.

Refer to the Adobe CC Extension SDK documentation for a full reference.

Utility functions

Finally, there is a small set of utility functions to encode and decode text and data to and from base64:

utf8_to_b64 (str)

b64_to_utf8 (base64str)

binary_to_b64 (binary)

b64_to_binary (base64str)

ascii_to_b64 (ascii)

b64_to_ascii (base64str)

Example:

var path = “/tmp/”; result = window.cep.fs.readFile(path, cep.encoding.Base64); if (0 == result.err) { //no error var base64Data = result.data; var data = cep.encoding.convertion.b64_to_utf8(base64Data); } else { …// handle error }

Finally…

When you’ve created your extension, you can distribute it via Adobe Exchange, which is a marketplace for extensions and content for Adobe products.

I hope you find this article useful. You can read more about HTML5 extensions by clicking through the following links:

You can also follow me on Twitter.