Vous êtes sur la page 1sur 63

FREE EXCERPT!

CC 2018 Edition

!e following content is a ~60 pages excerpt from the full eBook.


!e complete Adobe Photohop HTML Panels Development course
contains:

The Book

302 pages PDF, 15 Chapters of solutions to real-


world development problems.
ePub and Mobi digital versions included.

28 Panels

Each Chapter covers a topic, then custom-made


Panels (with fully commented code) dig deeper,
implementing the basic concepts shown in a more
advanced fashion.

Three hours HD video series

8 HD screencasts dealing with some of


the aspects covered in the book, adding
extra information and new sections on
specific subjects (such as ActionManager
code). Highly recommended to beginners!

The Full Package is available HERE!


Photoshop HTML Panels Development
Build and Market Adobe Creative Cloud extensions

Davide Barranca
This book is for sale at http://htmlpanelsbook.com

This version was published on 2017-10-22

This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.

© 2016 - 2017 Davide Barranca - Adobe® Photoshop® and Adobe® Creative Cloud® are registered
trademarks of Adobe Systems Incorporated in the United States and/or other countries. All other
trademarks are the property of their respective owners.
To my wife Elena
Contents

Foreword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv
Why I wrote this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv
Audience and Assumptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v
What this book is, and how to read it . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi
What this book is not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii
What you need to get started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii
Version History and Errata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viii
Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x
Piracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x

1. Photoshop Extensibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Plug-ins (Photoshop SDK) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Flash Panels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
HTML Panels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2. The HTML Panel Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7


CEP: Common Extensibility Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
CEF: Chromium Embedded Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
HTML and CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Javascript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Extendscript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Layers communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3. Setting up the environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11


Code editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Getting started: setting the Debug Flag . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Installation folders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Download the Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Storing projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
CONTENTS

4. Building up “Hello World!” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17


Take 1: Manifest.xml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Take 2: ExtendScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Take 3: Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Hello World wrap-up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

5. CSInterface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
JS interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
CEP Versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
evalScript() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
getSystemPath() and including multiple JSX . . . . . . . . . . . . . . . . . . . . . . . . . 38

6. Exchanging data between Panel and Host Application . . . . . . . . . . . . . . . . . . . 43


Passing primitive values from JS to JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Passing Objects from JS to JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Passing Objects from JSX to JS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Demo Panel: actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Demo Panel: Data exchange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

7. Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
No shortage of Events in town . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Host Application Events - ExtendScript Events in Photoshop . . . . . . . . . . . . . . . . 58
Host Application Events - CEP Application Events . . . . . . . . . . . . . . . . . . . . . 64
Custom ExtendScript Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Custom CEP Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
CEP Panel’s Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Demo Panel: Photoshop ExtendScript Events . . . . . . . . . . . . . . . . . . . . . . . . 71
Demo Panel: Photoshop CEP Events (LoseFocus) . . . . . . . . . . . . . . . . . . . . . . 73
Demo Panel: Photoshop Custom ExtendScript Events . . . . . . . . . . . . . . . . . . . . 74
Demo Panel: CEP Custom Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

8. Styling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Matching the Host Application UI look . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Synch with Photoshop Theme changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Flyout and Contextual menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Icons, Size and Retina Displays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Demo Panel: Flyout and Contextual menus . . . . . . . . . . . . . . . . . . . . . . . . . 95
Demo Panel: High PPI display . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100

9. Node.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Two of a kind . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Importing modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Contexts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
CONTENTS

Demo Panel: connecting to a REST service . . . . . . . . . . . . . . . . . . . . . . . . . . 112


Demo Panel: modularize JSX Events management . . . . . . . . . . . . . . . . . . . . . . 117

10. Store and retrieve Data locally . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124


Persistence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Using the Filesystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Web Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
IndexedDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Which one should I use? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Demo Panel: Persistence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Demo Panel: Node fs and nconf modules . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Demo Panel: Node.js presets module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

11. Javascript Frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154


What is the best JS framework for HTML Panels? . . . . . . . . . . . . . . . . . . . . . . 154
Newbies corner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Demo Panel: Angular JS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

12. Communicate with the WWW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168


Connect with the internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Download and open a file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Upload a file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Downloading and Uploading with Node.js . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Local Node.js servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Operating PS remotely . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
CORS: PostMessage and WebSockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
Generator integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Demo Panel: Flickr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Demo Panel: Upload (XMLHttpRequest) . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Demo Panel: Master / Slave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Demo Panel: No-CORS and postMessage . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Demo Panel: Socket.io . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Demo Panel: Generator server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209

13. Miscellanea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215


CEP - The other API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Inter-application communication (with Demo Panel) . . . . . . . . . . . . . . . . . . . . 218
Extensions types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
CEF command parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Localization (with Demo Panel) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Panel Licensing and Code privacy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227

14. Packaging and Distributing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234


CONTENTS

Signing and Timestamping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234


Panels Certificates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
Using the ZXPSignCMD commandline utility . . . . . . . . . . . . . . . . . . . . . . . . 237
Hybrid Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
Supporting older versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Advanced automation with Gulp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
Distributing, or the Art of minimizing Customer Support emails . . . . . . . . . . . . . . 255
Manual installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Adobe Add-ons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Adobe Extension Manager CLI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Third-party free ZXP installers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
PS Installer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Native installers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269

15. The Extensions Business . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270


Software is boring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Pricing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Marketplaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Your own storefront . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
Payment services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
Pricing (revisited) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Looking after your Customers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283

Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284

Copyright . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Foreword
We are all aware of the possibilities of automating and expanding the functionality of Adobe
applications. Many people, surely, would like to learn the art of programming, so as to add such
functionality, to make their workflow more productive and adapted to their personal needs.
Now that we can create Extensions for Creative Cloud applications, all this has been made possible.
Adobe Configurator, although misunderstood throughout its life, was the tool that allowed even the
less experienced to approach this magical world. Its removal from the scene has limited such access
to programmers, who can only navigate the process of creating Panels and Extensions in the new
HTML format with great difficulty, owing to the lack of adequate documentation.
Of course, nothing is difficult for programmers with considerable experience or a great aptitude for
the subject. Thanks to the talented Davide Barranca, who combines both attributes, we are now
fortunate enough to have a complete and comprehensive guide. He has learned everything in the
field with steady work, passion, dedication and many headaches! For this reason, his work really
needs no introduction, guarantees, or recommendations. A quick trip to the web will demonstrate his
capabilities, the quality and professionalism of his work and the support he has given to the entire
developer community. His blog has quickly gone viral and has offered solutions and information
valuable both to neophytes and the most experienced.
I have known Davide since his first forays into this field. What distinguishes him is his constant
study, his perseverance in the search for solutions, and the tenacity with which he deepens every
aspect of programming.
The difficulty of obtaining information and the sudden changes in requirements caused many, albeit
reluctantly, to abandon the development of extensions. To say nothing of the beginners who did not
enter the field for fear of being stranded on a desert island!
Like a boat in a fierce storm, or in a minefield, those who are not well equipped and aware of the
problems they face risk being shipwrecked. The solution is training, and the exchange of information
and experiences.
The interchange of ideas, the sharing of a project, the grasping of a new technique, is much easier in a
collaborative environment. Learning what others have experienced, and sharing common problems,
is often the easiest path, assuming that colleagues share the same goals. But how do we overcome
the lack of information?
Special-interest online discussion groups are today’s equivalent of that collaborative environment.
They are places where neophytes and experts can each find complete responses and partial solutions
to their problems. Google searches, blogs and private sites of independent developers, open source
communities such as the social network GitHub can also be quite useful for tapping into resources,
collaborating on a project, and/or putting information at the disposition of the community. So,
despite all the difficulties, there is some sharing of this ocean of knowledge.
Foreword ii

We must therefore know how to glean the exact information needed for our specific needs, to find
the one best suited to our particular problem. And time is also a factor: it is essential to get quick
answers, so as to concentrate more on the real problems instead of spending whole days in research,
and ending up with a fistful of nothing. It can be an exasperating experience that in most cases yields
only partial answers. And the information on how to create an HTML extension is as fragmented
as it could possibly be.
There is no one place to find all the explanations and the assembly of concepts, and the search for
it is likely to be frustrating and debilitating. What is lacking is a place where experts and novices
can find everything needed for a proper and rapid development, allowing free rein to creativity and
inventiveness.
This material, however, gets us only halfway there, since in most cases the transition from theory to
practice does not occur without problems. The rest of the process depends on our own energy and
capacity. But where can we find the correct, complete, exhaustive and effective presentation of the
basic material? For me there is no doubt, it is right here in the pages of this book.
Davide has supplied the missing link, the manual that each type of developer needs. Like the Never-
Neverland of Peter Pan, it is a place to discover yourself and explore your own passions and resolve
your own difficulties. He has put his knowledge and experience at our disposal without reserve, not
just to put us in a position to execute our projects but also to recognize pitfalls. The book is rich in
advice and tricks to get around obstacles and avoid confrontations with the evils that inevitably lurk
around the corner.
Every successful enterprise is the fruit of great work and great passion. Thanks to Davide’s
extraordinary teaching abilities, Photoshop HTML Panels Development leads the reader down a
stable and well-defined path. You will be taken step by step, with effective examples and clear
concepts, from a comprehension of the terminology, to a knowledge of the architecture on which
the extensions are based, to the completion of commercially ready products, and finally to the
considerations of how to market them. Above all, you will learn to comprehend the reasons and
concepts behind each step, and thus to achieve the autonomy to develop and create your own
extension. Adding to the completeness of the information, Davide has made all the resources
available on the web.
Photoshop HTML Panels Development is a book suitable for everyone. The beginner will find it a
great way to start, but even top experts will discover new and useful resources.
To the great envy of many, I was lucky enough to read this book during all stages of its drafting. I
myself have discovered ways to integrate and take advantage of new and interesting features, which
allowed me to bring to life certain older projects that were in an embryonic state because I had not
been able to overcome various problems by myself. Davide’s demonstrations and explanations will
be equally valuable for whatever my next projects may be.
I am sure that this book is well worth whatever time you spend on it. As for money, a friend once
told me that one should find at least five good reasons before spending it. I agree, and here are some
of mine.
Foreword iii

1. It lets me compare my work with that of another experienced programmer.


2. It offers new ideas and shows how to apply, with minimal effort, new and unexplored
techniques.
3. It is a compendium of resources that can be accessed very quickly.
4. The subject of this book is indispensable to my library, it is also the only one that comes to
HTML development panels.
5. There are possibilities to expand and possibly customize solutions that I have already found.

I could easily name more than five reasons but I think these are by far sufficient. I just want to add
a note for all of those who have asked me where to start in this field. The answer is now official.
Without this book will be a long and uphill road.
It is not hard to predict the question that comes spontaneously to your mind at this time. Why should
I pay any attention to the words of Giuliana Abbiati? Who is she, and what has she ever done to
qualify her to give me such advice?
I am perhaps the wrong person to ask this of, but I will give you an answer anyway. I could be any
one of you. Titles have little importance in my opinion. They do not always guarantee objectivity.
What is certain is that I have seen every problem involving the creation of panels and extensions,
and if I had had a book like this at my disposal it would have saved me from a thousand moments of
despair and dozens of unnecessary tests. I believe that the same would apply to Davide, with whom
I have shared such moments.
I hold Davide in the highest esteem, and I thank him not only for his work and for the free resources
that he has always put at the community’s disposal, but also for flattering me with the opportunity
to give my personal opinion about the quality and utility of this his first book, and last but certainly
not least for the sincere friendship that has bound us together for many years.
And now, the interesting part: Photoshop HTML Panels Development by Davide Barranca.
Giuliana Abbiati
Author of CPT - Channels Power Tool1 , and Dan Margulis’ PPW Panel2
1
http://www.cs-extensions.com/products/cpt/
2
http://www.moderncolorworkflow.com/free-resources
Introduction
Whether you’ve just bought this book or you’re reading here to make sure it fits your needs and level
of expertise, welcome to the introduction of Adobe Photoshop HTML Panels Development. This
Chapter will shed some light on Creative Cloud Extensions, the reason why they are an interesting
coding experience, and a profitable business too.

Why I wrote this book


Over the last seven years I’ve been devoting an increasing amount of time to the development of
Photoshop Scripts and Panels: either as products of mine to be sold in digital marketplaces, contract
jobs for clients, or helping colleagues and people asking for advice in public forums.
Photoshop and Creative Cloud Extensions, in general, have been evolving rapidly over time, and
documentation has not always been priority number one. Apparently, many people who found
themselves stuck with a particular coding issue related to Panels (a frequent fact of life that
everybody who’s ever been exposed to Adobe SDKs has a good knowledge of), to my great surprise,
have been starting to reach out for my help. And to a possibly even greater surprise of mine, it
seems like I’ve been, mostly, successful in providing them with guidance, reference code, or simply
my unopinionated point of view.
Photoshop and Creative Cloud Extensions are, as far as I understand them, largely a matter of
experience - e.g. avoiding common pitfalls or knowing best practices - in many cases I’ve just been
there before, I’ve seen how things evolved from the very beginning. Also, the learning curve involves
such a large variety of subjects that is hard for the newcomer (and everyone else as well) to focus
on the many Panels’ facets and the bigger plan at the same time.
This book is going to save you many hours of unrewarding head-scratching time and frustration -
which I’ve a huge personal collection of around the house - the main goal is to give you a substantial
productivity head start.
Over time I’ve found a way to take advantage of Photoshop extensions to make a profitable and self-
sustaining side-business. To date, I’ve built and marketed four paid products of mine, plus additional
five in collaboration with other developers - for sale in several, different e-stores - not to mention
free and open-source stuff.
Now, 40% of my total incomes as a Photoshop freelance is not time-based (e.g. working with
photographers doing post-production on hourly fees) and comes as monthly payments from software
vendors. Besides, programming didn’t eat away at my daytime job - I’ve been able to maintain
and grow my software business working when my usual Photoshop clients let me free, mostly on
weekends and by night. There are better ways to run this kind of trade, but here I am to prove that
Introduction v

Extensions can be turned into a profitable venture: the more you invest on it, the better the yield, of
course.
This book has been written to show you how I’ve been doing it.

Audience and Assumptions


It’s really important for me that your expectations, as a reader of this book, are met. On your side,
to exploit its value you must evaluate first whether it’s a good fit for your needs, skills and mindset
- because delusion most of the times is just a mismatched expectations’ by-product.
I do not want this course to be bought by everyone vaguely interested in HTML Panels development;
you do not want your time to be wasted on something that is not going to provide you with a tangible
profit. So please read along.
The title I’ve chosen is Adobe Photoshop HTML Panels Development for a reason - the software
I’ve fed my family thanks to, in the last 16 years, is Photoshop. Yet Panels structure and features are
largely shared among the whole lineup of Adobe’s Creative Cloud applications supporting HTML
Panels:

• Photoshop
• InDesign
• InCopy
• Illustrator
• Premiere
• Prelude
• After
• Animate
• Audition
• Dreamweaver
• Muse
• Bridge

Excluding some Event-specific parts, I’d say that most if not all of the code shown in this book, and
the whole marketing section, apply to any other Creative Cloud app mentioned above - which has
been corroborated by beta readers who work on InDesign and Illustrator - so you’re going to make
good use of this book even if your main focus is not on Photoshop.
HTML Panels are Web Applications hosted inside, and communicating with, Adobe Creative Cloud
apps. As a developer, you’ll be writing code related to the Panel’s functionality (using the HTML +
CSS + JS stack) and code related to the Host Application operations (Photoshop Scripting, InDesign
Scripting, etc. that is, ExtendScript language).
Introduction vi

If you are totally new to whichever form of coding, I’m afraid this book would be a waste of time and
money: I’d suggest you to take one of the many available free or paid courses on Web Development
first. Enjoy that stack? Come back here and you’ll find new challenges.
If you have an Adobe Configurator background and/or a very basic Javascript / ExtendScript
experience you’ll probably be OK until Chapter 6, that brings you to the point where you know
how build HTML Panels calling Actions in ActionSets, which is what a large majority of former
Configurator users are after. However, it won’t be the kind of book that you can skim through,
picking here and there and jumping to the Demo code straight away. If you’re looking for that kind of
thing, my friendly bit of advice is to look elsewhere. From Chapter 7 onwards, you’ll definitely need
supplementary, supporting material alongside this book, like dedicated CSS / JS / Node.js courses,
otherwise you won’t be able to retain and make the most of what is shown there - and it’s alot. Mind
you I don’t want to sound discouraging, but realistic: a path from the average Configurator user to
the average HTML Panels developer is indeed possible, and this book has been written also for you.
It just requires planning and extra resources, there’s no reason for me to skate over this and allure
you with copywriting tricks.
If you come from good old Photoshop scripting (that’s my own background, so I’m sympathetic),
I assume that you have a fine grasp of ExtendScript - which is nothing but a Javascript superset.
HTML Panels for sure have their own quirks, but you can definitely enjoy the process of learning
how to build them. Get ready to pay frequent visits to StackOverflow and the Mozilla DevNet, since
Web Development is the kind of tree that branches up to the stratosphere and beyond; luckily, if you
want to go into it in more depth, there’s no shortage of resources on the internet.
Conversely, if you are a Web Developer willing to exploit the power of Adobe Creative Cloud
applications, you’ll get easily into the part of the HTML Panel builder: Photoshop scripting will
look quite convoluted at first, but you’re going to get used to that in a reasonable amount of time.
In case you’re the King of the Keyboard and you know Photoshop like the back of your hand, please
have my seat and enjoy the ride.

What this book is, and how to read it


A couple of years ago a friend of mine, who happens to be a very talented Photoshop retoucher in
Milan, Italy, called me asking to meet for a few hours: “I need to get started with extensions! You
show me the basics, the pitfalls, documentation plus a list of reference links, and then I’ll carry on
with it myself”. Which in theory makes sense - but as they say: “In theory, theory and practice are
the same, but in practice… they’re not”.
This book aims to provide you with an extended, thorough answer to my friend’s ambitious yet
optimistic inquiry. I will introduce you to the topic of Photoshop and Creative Cloud panels: what
they are made of; what they are for; what they are not for. I’ll show you their architecture and inner
working - how Extensions are built and debugged, how to use JS a framework, how to access Node.js
modules, how to connect with a server, etc. The book is also a hands-on reference for a large number
of specific needs (which I know are very common because I see them pop in my Mail’s InBox), by
Introduction vii

examples: the way Panels deal with the host when it comes to app-specific Events, how to save
mutable data or successfully sign and timestamp a product for submission to the Adobe Add-ons or
other stores, etc.
Moreover, it is a collection of personal researches on the topic of Photoshop panels, countless hours
spent dealing with experienced people on forums, blogging, submitting bugs and feature requests
to, and discussing them with, Adobe’s engineers.
Adobe Photoshop HTML Panels Development is a tool that will give you an invaluable productiv-
ity head start, equipping you with an arsenal of tested and proven work solutions to the problem of
building and marketing Photoshop and Creative Cloud panels - that I put in practice myself running
my own daily business as an Extensions producer.
Especially If you’re green on development, I urge you to read it from start to finish, because it’s been
designed to slowly build up your skills: each chapter is a prerequisite of the one that follows, and
uses tools and knowledge coming from previous sections.
The book also contains 28 Demo Panels, a true bonanza! Don’t skim through the writing to focus
just on code, though: they usually are a more elaborate example of what’s been discussed during the
chapter, and without a solid understanding of the basics that have been laid out in the text, you’re
going to loose a lot of their potential learning value.

What this book is not


This is not “HTML Extensions Cookbook: 42 ready-made Panels to borrow code from”, nor “Learn
Photoshop Panels in 12 days and 4 full projects”.
I will be providing you with descriptions, recipes and lot of code samples as well, but my approach
is different from Cookbooks and Project Books. It’s a vast topic and I prefer to be more systematic
- furthermore, I like to introduce concepts first, then discuss the implementation, and eventually
show my interpretation (which is just my take, not code set in stone).
This material requires some squeezing of the brain juices also because, when it comes to OCOSA3 ,
Adobe’s HTML Panels are second to none.

What you need to get started


Coding Panels is now way more affordable than it used to be in the past when I started, and Flash, as
opposed to HTML, was mainstream. Back then, you could access Adobe Extension Builder 1 and 2
(the Eclipse plugins required to build Flash panels4 ) only by subscribing to a paid Adobe Technology
Partner Program - mine was Bronze, the cheapest, which included the Extension Builder download
as a benefit.
3
Office for Complication of Otherwise Simple Affairs.
4
Which doesn’t mean “panels hosted in Flash Pro”, but “panels coded in ActionScript”.
Introduction viii

Much water has passed under the bridge… Long story short, the Javascript libraries are now free for
you to grab on GitHub, so the requirement list shrinks to:

1. A licensed copy of Photoshop CC or newer (CC2014, CC 2015, CC 2015.5, CC2017…), or


another Creative Cloud app supporting HTML Panels.
2. A good text editor: pick up the one you are already comfortable with, or try:
• Sublime Text5 (paid)
• Adobe Brackets6 (free)
• Atom7 (free)
• Microsoft Visual Studio Code8 (free and surprisingly available for Windows, Mac and
Linux)
3. The ExtendScript ToolKit (aka ESTK), the Adobe script editor: find it in the Creative Cloud
downloads).
4. The Google Chrome browser for debugging.
5. Comfort items of your choice.

You can develop on both OSX and Windows - I strongly suggest you to test the other platform
before submitting your product to marketplaces, since running into platform-specific bugs is not
unfrequent. I use Parallels9 on a Mac, but different solutions are available.
Mind you, running Photoshop in a virtualized OS might require you to deactivate it on a different
machine, if you’ve exceeded the number of maximum Creative Cloud activations. Also, be aware
that virtualizing software such as VMWare10 can capture by default modifiers keys (e.g. the meta on
Mac), so you may need to remap some of your keyboard shortcuts.

Version History and Errata


The book has been written while I was working in Photoshop CC 2015.0.x (CEP6.0), then updated
to CC 2015.1.x (CEP 6.1), CC 2015.5 (CEP 7.0), CC 2017 (still CEP 7.0), and CC 2018 (CEP 8.0). Over
time Adobe has pushed some changes and/or introduced remarkable differences in the framework,
which made my panels sometimes break, sometimes work again: the never boring life of the third
party developer. I have fixed my code to comply to the latest available Photoshop version when I
judged that appropriate, while I’ve left it as it originally was in all those cases when, in my opinion,
it is opportune to wait for a bugfix on Adobe’s side.
5
http://sublimetext.com
6
http://brackets.io
7
https://atom.io
8
https://code.visualstudio.com
9
http://parallels.com
10
http://www.vmware.com
Introduction ix

This icon will signal you that a Panels’ issue has been resolved from a particular Photoshop
version onwards, and the code working around that problem has to be intended for
backwards compatibility only. Over time, I hope to fill this book with lot of Peace & Love
fingers.

Version 1.3.0 (CC 2018)


Fourth release, October 2017.

• New: added support to Photoshop CC 2018.


• New: added CC 2018 bug notes.
• New: expanded Chapter 14 with a note on Native Installers certificates.
• Fix: revised all the demo panels for CC 2018.
• Fix: included Bridge and Muse in the list of available applications.
• Fix: painfully revised Node.js support, that has changed once more in CC 2018.
• Fix: Tom Krcha resources on Generator are offline, links now point to Archive.org snapshots.

Version 1.2.0 (CC 2017)


Third release, November 2016.

• New: added support to Photoshop CC 2017 (even if it still features CEP7, like CC 2015.5).
• New: added a section on Native Mac and Windows installers to Chapter 14.
• New: added a workaround for Google Chrome (v54.x) broken Enter key in the Console.
• New: mentioned the Spectrum UI CSS in Chapter 8.
• New: I’ve now, once and for all, switched to Vue.js as my JS framework of choice, so this is
what I endorse now on Chapter 11.
• Fix: included Adobe Audition 8 in the list of supported applications.
• Fix: footnote (page 50).
• Fix: typos here and there, minor changes.

Version 1.1.0 (CC 2015.5)


Second release, July 2016.

• New: Adobe Photoshop CC 2015.5 (despite what you’d think, a major version: 17.0) has been
released June 21st, 2016. CEP has been bumped to version 7.0. I’ve updated all the book, where
needed, to cover the new version.
• New: mentioned Extendscriptr, page 8.
Introduction x

• New: added cefclient and Chrome Dev Tools scrolling fix, page 26.
• Fix: Gabe Harbs’ website link (sorry!), page 26.
• Fix: added a note on “User Cancelled Error” on CC 2015/Windows for the Actions panel, page
50.
• Fix: color in Panel’s icons is in fact allowed, page 92.
• Fix: typos here and there, minor changes.

Version 1.0.0 (CC 2015)


First release, March 2016.

Feedback
I’d love to hear from you! What is your background, what you’re going to build next, whether
you’ve found this book a good fit or not, and why. If you want to share your thoughts, let me know
at davide.barranca@gmail.com.

Piracy
This book is going to be pirated, like most of the published books, magazines and newspapers for
sale in the digital world. Some would also say that it’s a good thing, other would raise the “let the
one who has never sinned throw the first stone!” argument.
Since it’s very likely that you, the reader, have picked this book because you want to build a business
on top of Extensions yourself, I am confident that you have paid, or will very soon pay, to obtain a
legitimate copy and repay my efforts.
Because if you’re successful in building HTML Panels, you’ll be in my own shoes yourself - very
soon - and you don’t want this to happen to you too, do you? Thank you.
1. Photoshop Extensibility
“In the beginning the Universe was created.
This has made a lot of people very angry and been widely regarded as a bad move.”
-Douglas Adams

Overview
Let’s have a look at the bouquet of options you have as a Photoshop developer - HTML Panels are
not the only choice, and you might want to explore alternatives; either to add features, or broaden
retro-compatibility.
The Photoshop extensibility layer grew over time - as follow a brief overview of what is, and
historically has been, available.

Plug-ins (Photoshop SDK)


This is something we’re all familiar with, so that the layman calls everything (panels included) plug-
ins. Strictly speaking, you build a plug-in writing in some C-like language (C, C++, Objective-C),
using Apple XCode or Microsoft Visual Studio compiling with the Photoshop SDK11 .
There are several type of plug-ins, the most common of which:

• Filter: pixel crunching machines.


• Automation: accessing all Photoshop scriptable events.
• Format, Import and Export: input and output for specific devices or additional file formats.

In some cases, Plug-ins are actual stand-alone application whose interaction with Photoshop is
limited to getting and injecting back image data.
11
http://www.adobe.com/devnet/photoshop/sdk.html
1. Photoshop Extensibility 2

Filter Forge Plugin

Unless you have a good knowledge on both the language and the related tools, plug-ins programming
is possibly the steepest path on Photoshop enlightement.

Scripting
With a script you programmatically drive Photoshop; most of what is not available in the DOM
(Document Object Model - pretty much incomplete if compared to, say, InDesign), is within your
reach using ActionManager code: not the brightest example of API usability, but a tremendous power
at your disposal.
You can script Photoshop using AppleScript on Mac, Visual Basic on Windows, or Extendscript on
both platforms. In fact, there are three distinct layers of scripting available within Photoshop, as
follows.
1. Photoshop Extensibility 3

Extendscript
Extendscript (a superset of Javascript12 ) is the foundation of scripting in a variety of other Creative
Cloud applications (Bridge, Illustrator, InDesign, etc), and it’s what you’re going to use to impart
commands to the host app from within HTML Panels.
Using the peculiar ScriptUI class, you can build Graphic User Interfaces as well, like:

xbytor’s Image Processor Pro

Scripting and scripted dialogs are retro-compatible back to CS3 and earlier, if you don’t mind
distributing unobfuscated (plain) code.
12
ECMA-262, plus EX4 (ECMA357), plus Adobe’s non-standard stuff like Filesystem management, Reflection interface, operator overloading,
etc.
1. Photoshop Extensibility 4

TCP/IP (Connection SDK)


Less known option, yet worth exploring: from CS5 onwards, you can establish a TCP connection
with Photoshop and send/receive Extendscript messages and image data. But who is Photoshop
messaging with? For instance, but not exclusively, a mobile application, built in Java for Google
Android, Swift for iOS, or if you’re inclined even Adobe AIR.
I would say that you can use the Connection SDK with a framework such as Ionic13 too, but I’m just
speculating.

Generator
First released with Photoshop CC (14.1), Generator has been primarily marketed14 as a technology
that lets you export images in background, based on layer names. Actually, there’s much more: a
Node.js server that communicates with Photoshop via Kevlar API (Extendscript), and exposes an
Event based API for third-party plugins - mainly using Generator to access/extract resources from
within Photoshop. Panels can talk to Generator too.
From the very beginning, it has been open-sourced on GitHub15 .

Flash Panels
The first Photoshop Panel appeared back in CS4 and was based on a framework called PatchPanel,
which never left Adobe Labs16 (the Labs are sort of an experimental technology preview: that might,
or might not, find a way to actual Adobe products). According to conventional wisdom, one of the
main promoters of customizable panels has been the former Photoshop Product Manager John Nack,
now at Google. It was of course a Flash thing, because those were the Happy Flash Days at Adobe17 .
Flash Panels are supported from CS418 up to CC (Photoshop v.16) included: they were built in
Flex/ActionScript using Flex Builder (Adobe’s customization of Eclipse) as the IDE, with the help of
a plugin called Adobe Extension Builder. Strange as it may sound, Extension Builder v2.119 is still
available as a paid subscription for about EUR 10 per month, as opposed as the v3.020 targeted to the
newer HTML Panels, which is free.
One of the main catches of Flash Panels, with hindsight, is that you were lured to write all of your
Photoshop code directly in Actionscript - being the alternative to keep the Extendscript and just
13
http://ionic.io
14
http://blogs.adobe.com/photoshop/2013/09/introducing-adobe-generator-for-photoshop-cc.html
15
https://github.com/adobe-photoshop/generator-core
16
http://labs.adobe.com
17
Tons of Flash history and nostalgia in this article.
18
Photoshop CC2015.0.1 implements Node version 0.8.22 (log “process.version” to get it), CC2015.1.1, CC2015.5 and CC2017 use the io.js branch
v.1.2.0; CC 2018 has Node 7.7.4. Generator relies on a Node.js different version (currently 4.8.4 - find the Generator’s node executable in Adobe
Photoshop CC 2018.app/Contents/MacOS/ and run ./node -v).
19
http://www.adobe.com/it/products/adobe-extension-builder.html
20
http://labs.adobe.com/technologies/extensionbuilder3/
1. Photoshop Extensibility 5

evaluate it, inelegantly going back and forth from the Panel to Photoshop21 , and vice versa. Two
problems:

1. Actionscript is strongly typed, Extendscript is not. If you’re used to typecasting (i.e. implicitly
change the data type, say, from String to ArtLayer) you will spend an awful amount of time
trying to fix loosely typed code that suddenly stops working.
2. Developers who wrote and maintained Actionscript libraries for Photoshop have found
themselves empty handed when the wind changed to HTML - facing the burden to re-rewrite
their whole codebase back in Extendscript.

In order to let Flash Panels spread to a bigger audience, Adobe released Configurator22 , a visual, drag
and drop utility to create Panels without coding experience. Even if it didn’t support the whole range
of User Interface tools provided by Extension Builder, some remarkable extensions23 have been built
with it.
Its popularity grew slowly, yet steadily, over time - perhaps too slowly to match Adobe’s standards.
It has reached version 4, always belonging to the Adobe Labs; a promising HTML Widget was
implemented, but the exported Panel was still Flash based, its fate was sealed and Configurator has
then been abandoned. The main developer (who’s based in China I’d say, and then left Adobe)
announced on GitHub to be willing to port the project to HTML, but last time I checked, the
repository was still empty - I’m unable to find it now.

HTML Panels
Unless you’ve been living in a cave, you know what has happened to Flash24 . In four years or so a
new breed of Panels has emerged - now HTML is the reigning standard.
HTML Panels are supported from Photoshop CC (2013), which is the only bridge version that can
handle both Flash and HTML at the same time. We’re possibly allowed to think that they will last
longer, for it is a food that Photoshop itself eats. For instance, the “Library Panel”, the “Export As”
and “Recent Files” dialogs, the “Welcome” screen, they have been coded by Adobe as HTML Panels.
HTML Panel development is free, as opposed to Flash Panels. Extension Builder preview 325 is now
abandoned and won’t support the latest CC out of the box26 : you can build extensions using any
text editor and linking the open sourced libraries.
21
Ironically, this is actually what we’ve ended up doing in HTML Panels.
22
http://labs.adobe.com/downloads/configurator.html
23
http://www.cs-extensions.com/products/cpt/
24
http://www.commitstrip.com/en/2015/07/15/a-brief-history-of-flash/
25
http://labs.adobe.com/technologies/extensionbuilder3/
26
Latest version - which is still a Technology Preview - is dated Aug 1st, 2013. It can be tweaked to be used on Photoshop-latest, although I don’t
really recommend it.
1. Photoshop Extensibility 6

Being part of the developer community for some time now,


I’ve observed what IMHO looks like a shift in the way
Adobe thinks about HTML Panels. Please note that I have no
idea about what happens in their headquarters, so I’m just
speculating here.
At first, HTML Panels has been introduced as a logic plat-
form evolution – even if you couldn’t really compare, fea-
tures wise, a mature technology such as Flash to an emerg-
ing one, and many complained. Loudly. Shortcomings were
evident, yet optimists among us assumed that the gap would
be filled, eventually.
When the Photoshop Team has started implementing new
features as HTML Panels – e.g. the one I’ve mentioned – the
platform growth seemed to be more targeted to, and more
importantly driven by, internal use, rather than third-party
developers. Which might be a bad news. Documentation isn’t
priority #1; some features implementation has been modi-
fied, then reverted, then modified again, etc. Nonetheless, An example of HTML Panel
our community includes very obstinate developers, so rest
assured that gaps will be filled by the work of these wonderful people, and help is going to be given.
2. The HTML Panel Stack
2. The HTML Panel Stack 8

Flash Panels used to be AIR27 applications running within the Host App thanks to APE (Adobe Player
Embedded); not surprisingly, HTML Panels are web applications running within the Host App, such
as Photoshop. But what’s under the hood? How do we start building them?

CEP: Common Extensibility Platform


Formerly known as Creative Suite Extensible Services (aka CSXS) and later renamed Common
Extensibility Platform (aka CEP) is the whole suite of technologies embedded in Creative Cloud
desktop applications that makes the subject of this book possible - CEP has become synonymous
with HTML Extensions.
Let’s imagine a Panel as a stack: the technologies are actually integrated, but visualizing them as
layers might help.

CEF: Chromium Embedded Framework


That’s the main container: Photoshop implements CEF28 (not to be confused with CEP), an embedded
Google Chrome browser29 . CEF provides the technology needed to run web apps, and includes its
own Javascript rendering engine (the well known Google V830 , the very same Node.js is based upon).

HTML and CSS


When you look at a panel, what you see is the rendered HTML, styled. Nothing different from what
you’re used to - if elements on a page display correctly on Google Chrome, they’re supposed to work
in a Panel too.
According to Adobe, the following features are supported:

• Video
• Audio
• Drag and Drop
• Canvas
• SVG
• Web Workers
• Web Storage
• Web SQL Database
27
https://en.wikipedia.org/wiki/Adobe_AIR
28
https://en.wikipedia.org/wiki/Chromium_Embedded_Framework
29
The version implemented in Photoshop CC 2018 is CEF 3.2987, Chromium 57.0.2987.74.
30
https://en.wikipedia.org/wiki/V8_(JavaScript_engine)
2. The HTML Panel Stack 9

• Application Cache
• Server sent events
• Form input types
• Form elements
• Form attributes
• File API
• Session and Persistent Cookies

A note about Cascading Style Sheets. Adobe doesn’t provide any official CSS to be used in third
party panels: you’re free to implement the ones you like better, or borrow ideas used in Photoshop’s
own HTML panels. I’ll cover styling in a dedicate section.

Javascript
The ubiquitous JS is the foundation of Panel’s operations. You can plug in your framework of choice
such as AngularJS, in order to implement the MVC (Model View Controller) pattern; or make Ajax
calls, store data, send Database queries, interact with the server side, whatever you might need. As
I’ve mentioned above, the JS pertaining to a Panel is interpreted by the Chromium’s V8 engine - that
implements ECMAScript 5th version.
Also, Photoshop features a built-in31 instance of Node.js32 , so you’re free to require() code in your
JS, use core packages e.g. fs and http, grab available ones from NPM, or write your own modules.

Extendscript
Finally, the code driving the Host App is Extendscript (aka JSX, like its default file extension). All
the Photoshop heavy lifting - duplicate a document, apply a filter, etc - belongs to the JSX layer,
which has its own distinct Virtual Machine (VM).
I’d like to stress the above sentence: JS and JSX are interpreted and executed by two separate engines.
Sadly enough, Extendscript is stuck to ECMAScript 3rd version33 - that is to say: Photoshop will not
understand what the following line means (and throw an exception):

1 ["a", "b", "c"].indexOf("b"); // ReferenceError: indexOf is not a function


31
Photoshop CC2015.0.1 implements Node version 0.8.22 (log “process.version” to get it), CC2015.1.1, CC2015.5 and CC2017 use the io.js branch
v.1.2.0; CC 2018 has Node 7.7.4. Generator relies on a Node.js different version (currently 4.8.4 - find the Generator’s node executable in Adobe
Photoshop CC 2018.app/Contents/MacOS/ and run ./node -v).
32
http://nodejs.org
33
My own personal bet is that it will stick to ES3 indefinitely, for a variety of reasons that don’t fit in this book. Check out extendscriptr, an
independent project that compile ES5 and ES6, also known as ES 2015, back to ES3 / ExtendScript compliant code.
2. The HTML Panel Stack 10

Layers communication
So, if Javascript and Extendscript belong to different VMs, how is that the Panel magic can happen -
that is: what is that makes a Panel communicating with the Host Application (such as Photoshop)?
On one side, JS can use PlugPlug (a shared Adobe technology component) to send a message to the
JSX engine like “Dear Extendscript VM, can you evaluate this command for me?”, and the JSX layer
is kind enough to perform the task and return back the result to the JS for further processing.
On the other side, the JSX can emit Events - carrying a payload, so data can be transferred. Events
which the JS can listen to, and react accordingly; I’ll be covering in depth these mechanism, so just
don’t worry now.
To sum up, an HTML Panel is a modern web application based on HTML5, CSS3, JS (ES5 and
Node.js), which deals with the host application sending messages to, and listening for Events from,
the host app’s JSX Virtual Machine. Yet, from the sheer point of view of Photoshop operations,
nothing changes - there’s no new hook, everything’s based on good old scripting.
3. Setting up the environment
Code editors
A wise recommendation is: use what you’re already familiar and/or more productive with. You can
code HTML Panels with just a plain text editor, but let’s inspect some of the possibilities.

Adobe Extension Builder 3


It’s a free Eclipse plugin that is obviously unmaintained34 since mid-2013; yet it’s usable, if you don’t
mind tweaking preferences and manually update some files.

Adobe Extension Builder Preview 3

To date, it still is the closest thing to an Extension development IDE available (templates, code
completion, debugging, etc), but you have to like Eclipse. In order to be able to use it, follow these
steps.

• Download the Juno35 version (newer ones won’t work).


• Download Extension Builder36 .
34
If I were you, I wouldn’t hold my breath waiting for a revamped version of Extension Builder 3.
35
https://www.eclipse.org/downloads/packages/eclipse-classic-422/junosr2
36
http://labs.adobe.com/technologies/extensionbuilder3/
3. Setting up the environment 12

• Install Extension Builder from the Eclipse menu Help > Install New Software… You need to
Add… a new Local… repository pointing to the downloaded Extension Builder, then confirm
few times to have it finally installed.
• Create a File > New > Other.. and pick Application Extension Project from the Adobe
Extension Builder 3 folder.

You can visit Eclipse Help > Adobe Extension Builder 3 Start Page to find the (quite good even if
slightly out-of-date) documentation about it.
Mind you, you need to manually modify some of the preferences in order to target newer versions
of your Host App (Mac users: point to the exec within the App’s package):

Eclipse new Settings

Also, you need to manually update JS libraries code with newer ones (CSInterface.js, Vulcan.js,
etc. - which I’ll cover later on); finally, the manifest.xml needs to be changed too (see Chapter 4).
In order to do so, you need to find the hidden one in the .staged-extension/CSXS folder. A piece
of cake, no? Do yourself a favor and don’t use it.

Atom, Brackets, SublimeText


GitHub’s (free) Atom37 editor is a viable choice, yet for both the (free) Adobe Brackets38 and (paid,
but lovely39 ) Sublime Text40 there are plugins made by David Deraedt41 which help scaffolding new
CC Extension projects.
37
https://atom.io
38
http://brackets.io
39
Sublime Text future seems uncertain too, since its developer took the vow of silence and releases languish.
40
http://sublimetext.com
41
https://github.com/davidderaedt?tab=repositories
3. Setting up the environment 13

Sublime Text + CC Extension Plugin

Brackets also provide some great Intellisense for your own JS files, which is definitely a plus.

Visual Studio Code


When I’m writing this, there’s still room for improvement on the Intellisense side of this new,
free Microsoft multiplatform editor (Mac, Win, Linux). I would keep an eye on it, it looks really
promising.

Getting started: setting the Debug Flag


On each of your development machine, you need to somehow tell Photoshop that you’re going to
mess up a bit with Panels code, otherwise you’re going to run into a message complaining about a
missing signature. In short, you need to set the Debug Flag. Confused? Read along.
When Photoshop boots, it checks whether the installed Panels can be actually loaded and run; among
the rest, it looks for signing/timestamping - an important topic that will deserve its own Chapter
later in this book. The relevant bit of information that you need right now is: Photoshop doesn’t
want you to modify the installed Panels’ code, it’s a mortal sin, and the Panel won’t load anymore.
Since, during the development, modifying code (and/or cursing) is your prominent activity, you
would rather prefer Photoshop not to be that picky about the Panel constantly changing its source.
3. Setting up the environment 14

Luckily, the so-called Debug Flag can switch off this behaviour and bypass the extension signature
check.
On a Mac, fire the Terminal and type:
defaults write com.adobe.CSXS.8 PlayerDebugMode 1

Which is the same as finding the file ∼/Library/Preferences/com.adobe.CSXS.8.plist, opening


it with XCode or any other .plist editor, and adding a new PlayerDebugMode Key of type String
with value “1”.
In order for the changes to apply, you might need to either restart OSX (quicker), or open Activity
Monitor and kill all the running instances of cfprefsd - this will force a new .plist scan to update
the cache.
For Windows: run Regedit, browse to:
HKEY\_CURRENT\_USER/Software/Adobe/CSXS.8

then add a new PlayerDebugMode key of type String with value “1”.
Mind you: in case you want to test your panel on different versions of Photoshop, you need to add
the debug flag to each and every one of the required CSXS files, which Photoshop matching versions
are as follows:

• com.adobe.CSXS.8 = CC 2018
• com.adobe.CSXS.7 = CC 2015.5 and CC 2017
• com.adobe.CSXS.6 = CC 2015
• com.adobe.CSXS.5 = CC 2014
• com.adobe.CSXS.4 = CC

Installation folders
Now that you can momentarily forget about extension signatures, it’s time to know where HTML
Panels belong in the User’s HD - their path. It’s a slightly more complicate matter than I would find
appropriate, so I’ll keep it as short as possible for you.

1. Of course the path is different on OSX and Windows.


2. It depends on whether you want the Panels to be available for all the Users of the computer,
or the currently logged User only.
3. It also depends on the Photoshop version you’re targeting (I won’t consider anything below
CC).
3. Setting up the environment 15

The path for Windows is:


(User): C:\Users\<username>\AppData\Roaming\Adobe\<CEPVersion>\extensions\
(System): C:\Program Files (x86)\Common Files\Adobe\<CEPVersion>\extensions\
While on Mac:
(User): ∼/Library/Application Support/Adobe/<CEPVersion>/extensions
(System): /Library/Application Support/Adobe/<CEPVersion>/extensions
Mind you, the first is the User’s Library, the second is the System’s Library42 .
<CEPVersion> is CEPServiceManager4 for Photoshop CC, CEP for any next version so far (CC 2014,
CC 2015, CC 2015.5, CC 2017, CC 2018). In case the /extensions folder doesn’t exist, feel free to
create it.
It’s still debatable whether you should deploy extensions at the User’s or System’s level - I prefer
the former, which possibly leads to fewer permission issues.

Download the Libraries


Go to the CEP843 GitHub repository (or whatever CEP major version is the one that you’re interested
into), and grab the following files:

• CSInterface.js
• Vulcan.js
• AgoraLib.js

Keep them handy because you’ll need to link them in your extensions.

Storing projects
Over the years I’ve tested few different setups, and now I’ve settled to the following one.
As a single developer, I use Git44 as a Version Control System, pushing to BitBucket45 : which allows
unlimited and free private repositories (also their SourceTree46 Git client is my favorite).
42
You don’t need to deploy on both folders, either the User or the System
43
https://github.com/Adobe-CEP/CEP-Resources/tree/master/CEP_8.x
44
https://git-scm.com
45
http://bitbucket.org
46
https://www.sourcetreeapp.com
3. Setting up the environment 16

Each project has of course his own directory/repository, which belongs to a Dropbox local folder
as a safety net. Mind you: some Cloud aggregators47 , such as the otherwise great odrive48 , won’t
backup Git repos.
Then, I create a Symbolic Link49 from each of my Dropbox development folders, to the Installation
Folder. On Mac (open Terminal), it’s like:

ln -s /Users/<you>/Dropbox/Projects/ALCE /Users/<you>/Library/Application\ Suppo\


rt/Adobe/CEP/extensions/ALCE

This way I can keep coding on my backup-ed, Git managed, local Dropbox folder without the need
to move stuff around to deploy and test on Photoshop.

Windows users: I’ll be using Linux/Mac-style commands on the commandline throughout


the book. I suggest you to install Cygwin50 so that you can run commands just as they’re
written here.

47
Aggregators are services which allow you to manage multiple Cloud accounts at once, such as Dropbox, Google Drive, Box, OneDrive, etc.
48
http://odrive.com
49
Which is different than creating an alias: symlinks work, aliases don’t.
50
https://www.cygwin.com
4. Building up “Hello World!”
Greeting the world is (by law) the first step in every language, and who am I to break traditions.
In fact we’ll be coding not one but three such panels, and each exercise is nothing but a pretext to
tell you about some very important extension feature. So get ready and don’t just skip to the next
chapter, I can read your mind.

Take 1: Manifest.xml
Create a Hello World folder in the appropriate /CEP/extensions path to contain the whole project,
then create a new index.html file with the following content:

1 <!doctype html>
2 <html>
3 <head>
4 <title>Hello World!</title>
5 </head>
6 <body>
7 <h1>Hello World!</h1>
8 </body>

No really, do it.
I’m afraid if you reboot Photoshop and look in the Window > Extensions menu, you won’t see it
there.
Photoshop needs quite a lot of extra information about your extension, such as its unique ID,
the panel size, the version of the Host App it supports, etc. All this (and much more) goes into a
manifest.xml file that mandatorily has:

1. To exist.
2. To belong to a CSXS folder in the project’s root. If it’s missing, or mistyped (which is not
unfrequent), the panel won’t load.

So, the simplest extension’s tree ever is:


4. Building up “Hello World!” 18

.
├── CSXS
│ └── manifest.xml
└── index.html

You can look at existing extensions’ manifest to check what the available tags are, but as follows is
a pretty standard one for our super minimal Hello World:

Example of a manifest.xml

1 <?xml version="1.0" encoding="UTF-8"?>


2 <ExtensionManifest
3 Version="6.0"
4 ExtensionBundleId="com.example.helloworld"
5 ExtensionBundleVersion="1.0.0"
6 ExtensionBundleName="Hello World"
7 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
8
9 <ExtensionList>
10 <Extension Id="com.example.helloworld.panel" Version="1.0" />
11 </ExtensionList>
12
13 <ExecutionEnvironment>
14 <HostList>
15 <Host Name="PHXS" Version="16.0" />
16 <Host Name="PHSP" Version="16.0" />
17 </HostList>
18
19 <LocaleList>
20 <Locale Code="All" />
21 </LocaleList>
22
23 <RequiredRuntimeList>
24 <RequiredRuntime Name="CSXS" Version="6.0" />
25 </RequiredRuntimeList>
26 </ExecutionEnvironment>
27
28 <DispatchInfoList>
29 <Extension Id="com.example.helloworld.panel">
30 <DispatchInfo >
31
32 <Resources>
33 <MainPath>./index.html</MainPath>
4. Building up “Hello World!” 19

34 <ScriptPath>./jsx/photoshop.jsx</ScriptPath>
35 </Resources>
36
37 <Lifecycle>
38 <AutoVisible>true</AutoVisible>
39 </Lifecycle>
40
41 <UI>
42
43 <Type>Panel</Type>
44 <Menu>Hello World!</Menu>
45
46 <Geometry>
47 <Size>
48 <Height>150</Height>
49 <Width>300</Width>
50 </Size>
51 <MinSize>
52 <Height>100</Height>
53 <Width>150</Width>
54 </MinSize>
55 <MaxSize>
56 <Height>200</Height>
57 <Width>350</Width>
58 </MaxSize>
59 </Geometry>
60
61 <Icons>
62 <Icon Type="Normal">./icons/iconNormal.png</Icon>
63 <Icon Type="RollOver">./icons/iconRollover.png</Icon>
64 <Icon Type="Disabled">./icons/iconDisabled.png</Icon>
65 <Icon Type="DarkNormal">./icons/iconDarkNormal.png</Icon>
66 <Icon Type="DarkRollOver">./icons/iconDarkRollover.png</Icon>
67 </Icons>
68
69 </UI>
70 </DispatchInfo>
71 </Extension>
72 </DispatchInfoList>
73 </ExtensionManifest>

Salient elements:
4. Building up “Hello World!” 20

• Version: this is tricky, because it refers to the version of the Common Extensibility Platform
(CEP - covered in following chapters), and must correspond to the value set in the Require-
dRuntime CSXS Version. For CC it’s "4.0", CC 2014 is "5.0", CC 2015 is "6.0", CC 2015.5
and CC 2017 is "7.0", CC 2018 is "8.0".

Photoshop CC 2018.0 aka 19.0.0 does not support Version="8.0". It should, if only because
this is the way things were set in the last four years, from 4.0 up to 7.0: RequiredRuntime
and ExtensionManifest do match the CEP version number. Whether it’s a bug that Adobe
is going to fix or not, is you use 8.0 your panel is not going to show up in the Extensions
list, so stick to 7.0.

• ExtensionBundleId: an extension can bundle multiple Panels, and this is the unique ID for
the Bundle - required even if yours is a one-panel-only Bundle.
• ExtensionBundleVersion: the current version of your Bundle.
• Extension Id: the unique ID for the extension (best practice is to add a .panel or .panel1 to
the ExtensionBundleId), and the Version there is finally your extension version.
• HostList: contains the Host tag, which has the
– Name: see the Debugging section for a list of 4chars codes of all the applications
supported. Mind you, for Photoshop you need to explicitely use both "PHSP" and
"PHXS"51 .
– Version: the supported version of the host app. Either an Array such as "[16.0,16.9]"
(from 16.0 to 16.9), where square brackets mean “included” and round parens mean
“excluded”; or a straight number like "15.0", which means from 15.0 onwards with no
upper limit. Please don’t do "[16.0,9999.9]" as I’ve seen.
• MainPath: the HTML entry point of the Panel.
• ScriptPath: the JSX entry point of the Panel (covered below).
• Geometry: sets the default (required), max and min (optional) size of the panel.

CEP7/8 updates
Starting with Photoshop CC2015.5 you’re allowed to move the <HostList> node inside <Extension>,
that is: specify a custom Host app on a per extension basis, like:

51
They refer to Photoshop and Photoshop Extended, a relic from the past when they were marketed as different products. See here the reason
why you need them both in the manifest.xml.
4. Building up “Hello World!” 21

1 <!-- ... -->


2 <ExtensionList>
3 <!-- ... -->
4 <Extension Id="com.example.HelloWorld.pspanel" Version="7.0.0"/>
5 <Extension Id="com.example.HelloWorld.dwpanel" Version="7.0.0"/>
6 <!-- ... -->
7 </ExtensionList>
8 <ExecutionEnvironment>
9 <HostList>
10 <Host Name="DRWV" Version="15.0" />
11 <Host Name="PHXS" Version="16.0" />
12 <Host Name="PHSP" Version="16.0" />
13 </HostList>
14 </ExecutionEnvironment>
15 <DispatchInfoList>
16 <!-- ... -->
17 <Extension Id="com.example.HelloWorld.pspanel">
18 <HostList>
19 <Host Name="PHXS" />
20 <Host Name="PHSP" />
21 </HostList>
22 <!-- ... -->
23 </Extension>
24 <Extension Id="com.example.HelloWorld.dwpanel">
25 <HostList>
26 <Host Name="DRWV" />
27 </HostList>
28 <!-- ... -->
29 </Extension>
30 <DispatchInfo>
31 <!-- ... -->
32 </DispatchInfo>
33 <!-- ... -->
34 </DispatchInfoList>

This is because your Extension can bundle multiple Panels (you’ll see this later on): this way you
can customize a Panel for, say, ID, one for PS, etc. To let you taste the salty sea of HTML Panels just
grab the manifest.xml I’ve provided, save and reboot Photoshop. Now find the “Hello World” panel
in the Window > Extensions menu.
4. Building up “Hello World!” 22

Problems running the Extension?


Try downloading the provided source code and compare it with yours. Is something
missing? Chances are that there’s some error in the manifest.xml, like a curvy quotation
marks (“ ”) instead of dumb ones (" "), or mismatching CSXS Version.
To validate the manifest, download the ExtensionManifest_v_7_0.xsd52 file53 and upload
it alongside with your own manifest to this Schema Validation54 service.

Take 2: ExtendScript
An important and still missing piece of the puzzle is the interaction with the Host App - Hello
World must somehow get in touch with Photoshop. As you remember from the manifest.xml, the
JSX entry point (referred to the extension root) is set there as shown in this excerpt:

<Resources>
<MainPath>./index.html</MainPath>
<ScriptPath>./jsx/photoshop.jsx</ScriptPath>
<CEFCommandLine/>
</Resources>

The above means: as soon as the Panel needs it55 , the content of the ./jsx/main.jsx file is going to
be read and evaluated in the JSX engine. If it contains statements, they’re going to be executed; if it
contains function declarations, they will stick into the JSX Virtual Machine, ready to be called later
if/when needed, you’ll see in a minute how.
Let’s group files more systematically - adding to the panel a js, jsx and css folder, the tree becomes:

.
├── CSXS
│ └── manifest.xml
├── css
│ └── styles.css
├── index.html
├── js
│ ├── libs
│ │ └── CSInterface.js
│ └── main.js
└── jsx
└── photoshop.jsx
52
https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_7.x/ExtensionManifest_v_7_0.xsd
53
Or the version of the CEP you’re targeting: there are .xsd files for CEP7, CEP6 and CEP5.
54
http://www.corefiling.com/opensource/schemaValidate.html
55
The JSX isn’t really evalued at Panel loading, but only when the first .evalScript() call is fired.
4. Building up “Hello World!” 23

The improved index.html now contains a button (small steps I know):

index.html

1 <!doctype html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <link rel="stylesheet" href="css/styles.css"/>
6 <title>Hello World!</title>
7 </head>
8 <body>
9 <div id="content">
10 <button id="btn_test">Say Hello</button>
11 </div>
12 <script src="js/libs/CSInterface.js"></script>
13 <script src="js/main.js"></script>
14 </body>
15 </html>

and the JSX has code for popping up an alert:

photoshop.jsx

1 function sayHello(){
2 alert("Hello from ExtendScript");
3 }

As you might foresee, a button click will trigger the Photoshop


alert - that is: we will bridge the gap from the panel to the host
app.
Please notice that there’s a ./js/libs folder containing the CSIn-
terface.js file, that in the previous chapter I’ve recommended
you to download from the CEP GitHub page. For the time being,
think about CSInterface as the JS bridge between you and CEP
features implemented in Photoshop; the next Chapter is going to
give you an extensive coverage of what is CSInterface all about.
Our main.js file contains:
Hello World take 2
4. Building up “Hello World!” 24

main.js

1 (function () {
2 'use strict';
3
4 var csInterface = new CSInterface();
5
6 document.getElementById('btn_test').addEventListener('click', function () {
7 csInterface.evalScript('sayHello()');
8 });
9
10 }());

Let’s have a deeper look at it.

1. Everything is wrapped with an Immediately-Invoked Function Expression (aka IIFE): it


creates a block scope and avoids polluting the global environment.56
2. The CSInterface class is instantiated and stored in a variable.
3. A listener for the click event is attached to the button with id="btn_test" (the only button
our poor html has).
4. In the callback, the csInterface.evalScript method is used to send to the Photoshop JSX
engine the 'sayHello()' string for evaluation.

Hello World take 2 in action

As a result, when you press the Panel’s Say Hello button, its click event listener fires the callback,
which in turn says: “Hey Photoshop, does 'sayHello()' mean something for you?”. Photoshop
in turn looks whether the manifest.xml knows about any JSX file to parse (“here it is Sir, it’s
photoshop.jsx”) and hands it to its JSX engine. Finally sayHello() is run, and the alert pops up.
56
Does that sound like Sanskrit to you? Read this clear article to understand more about it.
4. Building up “Hello World!” 25

JSX silent failures


An annoying trait of the ExtendScript implementation in HTML Panels is that if your JSX
code contains errors such as typos, it will fail silently: that is, you have no clue about the
reason why it doesn’t behave as you think it should.
As an example, sabotage the sayHello function mistyping alerr instead of alert. If you
run this in ESTK57 you will get ReferenceError: alerr is not a function as soon as you
try calling sayHello. This is not the case when the above happens in the context of an
HTML Panel, so be aware. Mind you, wrapping the whole JSX content with a try/catch
block won’t work.
Also, if the photoshop.jsx file is totally empty (that is, no chars), any
evalScript() call that you might do not referencing existing functions (e.g.
csInterface.evalScript("alert('Hello!')") will fail. Put at least some chars in
there, a comment, whatever.

We’ll make extensive use of both CSInterface methods and ExtendScript code in the next chapters,
so if this Hello World take 2 exercise has left you with unanswered questions (is there a way to
transfer a payload between JS and JSX? Is the other way around possible?), be aware that we’ll
touch those topics again and again, and you won’t miss code examples.

Take 3: Debugging
The Hello World third iteration is about debugging, an activity we all love. How do you do it?
Remotely is the answer - i.e. the panel will act as a server and you’ll be connecting to it.
In the root folder of your extension, create a blank file called .debug, which makes it hidden58 .

You can use your Text Editor for this task, or the Terminal (find it in the Applications/Utilities
folder). First, cd in the appropriate location (you can see in the above screenshot that Folders with
spaces in the name are escaped with a \ which is the default when you drag and drop a Folder from
Finder in the Terminal window), then touch the .debug file to create it.
This file needs to be formatted as an XML and should contain information about the ID of your
extension (i.e. it must match the ID specified in the manifest.xml), and the host/port (in the range
1024 – 65534) you want to connect through.
57
ExtendScript Toolkit.
58
On OSX, a filename that starts with a dot is hidden.
4. Building up “Hello World!” 26

Example of a .debug file

1 <?xml version="1.0" encoding="UTF-8"?>


2 <ExtensionList>
3 <Extension Id="com.example.helloworld.panel">
4 <HostList>
5 <!-- Comment Host tags according to the apps you want to support -->
6 <!-- Photoshop -->
7 <Host Name="PHXS" Port="8088"/>
8 <!-- InDesign -->
9 <Host Name="IDSN" Port="8087" />
10 <!-- InCopy -->
11 <Host Name="AICY" Port="8086" />
12 <!-- Illustrator -->
13 <Host Name="ILST" Port="8085"/>
14 <!-- Premiere -->
15 <Host Name="PPRO" Port="8084" />
16 <!-- AfterEffects -->
17 <Host Name="AEFT" Port="8083" />
18 <!-- Prelude -->
19 <Host Name="PRLD" Port="8082" />
20 <!-- FLASH Pro -->
21 <Host Name="FLPR" Port="8081" />
22 <!-- Dreamweaver -->
23 <Host Name="DRWV" Port="8080" />
24 <!-- Audition -->
25 <Host Name="AUDT" Port="8079" />
26 <!-- Muse -->
27 <Host Name="MUSE" Port="8078"/>
28 <!-- Bridge -->
29 <Host Name="KBRG" Port="8077"/>
30 </HostList>
31 </Extension>
32 </ExtensionList>

Now, while your Photoshop extension is open, point the Chrome browser to http://localhost:8088
(of course use the port you’ve set in the .debug file). You should see something like this:
4. Building up “Hello World!” 27

Localhost:8080

When you click the Hello World link (which is the title tag set in the index.html) the Chrome
Developer Tools will open and you’ll be able to inspect/debug your extension, set breakpoints, log
messages, like any other web application. Introductory tutorials can be found on DevTools page59 ,
Code School60 , TutsPlus61 .
Breakpoints can be set in the Sources tab, refreshing then the view with Command or Control + R
in order to restart the panel. Mind you, the Chrome Developer Tools cannot reach the JSX level –
it’s just for the HTML panel and its JS; if you’re wondering, a debugger call in the JSX doesn’t fire
up ESTK. If you want to log from JSX in the Chrome Console, you need to use Custom JSX Events
- see Chapter 7.

Chrome Developer Tools

59
https://developer.chrome.com/devtools
60
https://www.codeschool.com/courses/discover-devtools
61
http://code.tutsplus.com/courses/chrome-developer-tools
4. Building up “Hello World!” 28

Let me list few handy debugging caveats.

Kill the Cache


You will save hours of frustration installing a Google Chrome extension called Cache Killer62 : as the
name suggests, it prevents Chrome Developer Tools from loading a cached version of your panel,
driving you crazy. A typical scenario is you fixing code, relaunching the extension, still getting
problems - until you find out that Chrome didn’t retrieve the latest corrections and still shows you
the old panel. Thanks to the InDesign developer Gabe Harbs63 who pointed me to it.

Console issues
If you can’t scroll the Chrome Developer Tools Console (that is, when it’s full you can’t see any
more logged lines) the workaround is found here64 – basically you need to inject this CSS to make
it work again:

html /deep/ * { min-width: 0; min-height: 0; }

In case, instead, the return key is not working (that is to say: the cursor goes to a new line, but the
expression in the Console is not evaluated), please refer to this topic65 . A working solution is to use
not Google Chrome but Chromium itself. You can download Chromium here66 – theoretically you
should pick the version that matches the current CEF.

Using cefclient
In the Adobe-CEP GitHub repository you can download cefclient67 , either Mac or Windows. It’s,
well, a CEF client that you can use instead of Google Chrome: be aware that (at least on Mac),
you need to pass a custom flag to the executable or it won’t connect with Photoshop. So the actual
Terminal command is:

cd <The Folder Where cefclient.app belongs>


./cefclient.app/Contents/MacOS/cefclient --off-screen-rendering-enabled

Hello World wrap-up


Hopefully this chapter has raised more curiosities than the information it has given - JSX evaluation,
CSInterface, debugging and also the manifest subtleties will deserve extra mentions in the following
pages; I’d say that for a Hello World there’s already too much on the table, see you in the next chapter.
62
https://chrome.google.com/webstore/detail/cache-killer/jpfbieopdmepaolggioebjmedmclkbap?hl=en
63
http://in-tools.com/
64
https://github.com/Adobe-CEP/CEP-Resources/issues/35#issuecomment-165759781
65
https://github.com/Adobe-CEP/CEP-Resources/issues/78
66
https://www.chromium.org/getting-involved/download-chromium
67
https://github.com/Adobe-CEP/CEP-Resources/tree/master/CEP_8.x
5. CSInterface
In the previous chapter you’ve been introduced to the CSInterface.js library, using its evalScript()
method that sends strings to the JSX Virtual Machine for evaluation. There’s a lot more in there, so
let’s start exploring.

JS interface
As the name suggests, CSInterface.js is a Javascript interface to CEP features implemented in the
host application with native code. In other words, Photoshop exposes some CEP hooks that you can
reach using JS code from within an HTML Panel.
Mind you: the CSInterface.js file must to be linked in the index.html (or whatever it is called
the HTML entry point of your extension).
There is no official documentation for the CSInterface.js library, yet the source code is commented
using the JSDoc68 standard, as the following snippet shows:

Excerpt of CSInterface.js

1 /**
2 * Resize extension's content to the specified dimensions.
3 * 1. Works with modal and modeless extensions in all Adobe products.
4 * 2. Extension's manifest min/max size constraints apply and take precedence.
5 * 3. For panel extensions
6 * 3.1 This works in all Adobe products except:
7 * * Premiere Pro
8 * * Prelude
9 * * After Effects
10 * 3.2 When the panel is in certain states (especially when being docked),
11 * it will not change to the desired dimensions even when the
12 * specified size satisfies min/max constraints.
13 *
14 * Since 6.0.0
15 *
16 * @param width The new width
17 * @param height The new height
18 */
68
http://usejsdoc.org
5. CSInterface 30

19 CSInterface.prototype.resizeContent = function(width, height)


20 {
21 window.__adobe_cep__.resizeContent(width, height);
22 };

You can generate your own HTML (or Markdown) documentation installing JsDoc via npm:

sudo npm install -g jsdoc

and then calling it against the library:

jsdoc /Users/davidebarranca/Adobe/CEP_6.x/CSInterface.js

An out folder is generated in your present working directory, containing the HTML doc.

CSInterface Documentation

Another way to explore the CSInterface object is to play with it in the Chrome Developer Tools
console. Open the Hello World panel in Photoshop then connect to localhost:8088 in Chrome and
have fun with code completion:
5. CSInterface 31

Chrome Developer Tools code completion with CSInterface object

You see that - besides Event related stuff - available functions are mostly getters and setters:

Playing with CSInterface getters in the Console

Some of the methods should be self-explanatory, such as:


5. CSInterface 32

csInterface.openURLInDefaultBrowser("http://www.google.com");
csInterface.closeExtension();
csInterface.requestOpenExtension("com.example.jsxDemo");

Others are a tad more cryptic at first, like:

csInterface.initResourceBundle()

A quick look at the JSDoc reveals that it’s about Localization. You’ll encounter most of them
throughout the book, so feel free to be slightly disoriented now.

CEP Versions
It is important to understand that different Photoshop versions implement different CEP features,
which in turn correspond to different CSInterface.js files to link in your panels. As follows the
CEP version history against Photoshop:

Creative Cloud version PS Internal version CEP version


Photoshop CC 14.x CEP 4.x
Photoshop CC 2014 15.x CEP 5.x
Photoshop CC 2015 16.x CEP 6.x
Photoshop CC 2015.5 17.x CEP 7.x
Photoshop CC 2017 18.x CEP 7.x
Photoshop CC 2018 19.x CEP 8.x

In theory a CEP major update is relased at each major CC release, and a newer CSInterface.js
library is provided on GitHub for you to use in your code. But it’s hard to predict what the future
will bring, given that CC2015.569 , despite the naming convention, is a major Photoshop version
(18), and CC 2017 hasn’t brought CEP8 as we would have expected (as a consequence, there’s no
new CSInterface.js as well). CEP8 came with CC 2018, but Version="8.0" doesn’t work yet in
manifest.xml and as a matter of fact CSInterface.js hasn’t changed from CC 2015.5. Adobeland.

How do you deal with retro-compatibility? First, you must remember that you need to declare the
CEP version in the manifest.xml in two places:

69
Nobody knows the reason why CC 2015.5 is in fact a major version. My theory is that must be an Indian curse on the number 5. Photoshop
went from version 5 to 5.5, from CS5 to CS5.5 (actually 5.1 but within the CS5.5) and now from CC 2015 to C C2015.5.
5. CSInterface 33

Excerpt of manifest.xml

1 <?xml version="1.0" encoding="UTF-8"?>


2 <ExtensionManifest
3 Version="7.0"
4 ExtensionBundleId="com.example.helloworld"
5 ExtensionBundleVersion="1.0.0"
6 ExtensionBundleName="Hello World"
7 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
8 <ExtensionList>
9 <Extension Id="com.example.helloworld.panel" Version="1.0" />
10 </ExtensionList>
11 <ExecutionEnvironment>
12 <HostList>
13 <Host Name="PHXS" Version="18.0" />
14 <Host Name="PHSP" Version="18.0" />
15 </HostList>
16 <LocaleList>
17 <Locale Code="All" />
18 </LocaleList>
19 <RequiredRuntimeList>
20 <RequiredRuntime Name="CSXS" Version="7.0" />
21 </RequiredRuntimeList>
22 </ExecutionEnvironment>
23 <!-- Lot of stuff follows... -->

In the above example, the Version="7.0" found in line 3 and 20 refers to the CEP version, and in
fact we’re targeting Photoshop CC 2017 (see lines 13 and 14). In case you want to support Photoshop
CC as well, use Version="4.0" and remember to change the Host Version to Version="14.0" - that,
as you remember, means: from 14.0 onwards with no upper limit.
Mind you, the CSInterface.js library is retro-compatible, so you can keep linking the greatest and
latest found on GitHub. Of course linking a newer CSInterface.js doesn’t automagically mean
the possibility to use new features: for instance, Panel resizing at runtime is available since CEP 6
(Photoshop CC2015) and even if you link CSInterface.js version 6, it won’t work in Photoshop CC
2014.
To sum up: as a rule of thumb, specify the lowest CEP and Host App version that yor panel supports
in the manifest.xml, and link the newest CSInterface.js library available. Then, you can do your
check at runtime against the CEP version, such as:
5. CSInterface 34

1 var csInterface = new CSInterface();


2 var currentAPI = csInterface.getCurrentApiVersion();
3 // {minor: 0, micro: 0, major: 8}
4 if (currentAPI.major >= 7) {
5 // Do something that is featured in CEP 7 onwards
6 } else {
7 // Fallback for earlier CEP versions
8 }

In case you’re dubious, the above goes in the main.js (and not in the JSX) since all CEP stuff belongs
to the JS side of the world.

evalScript()
We’ve already used csInterface.evalScript()70 in the Hello World exercise, yet it’s such a crucial
method that it deserves its own section.

Callback
If you look at the CSInterface.js source code, you see that it accepts two parameters, the second
one being optional:

evalScript source in CSInterface.js

1 /**
2 * Evaluates a JavaScript script, which can use the JavaScript DOM
3 * of the host application.
4 *
5 * @param script The JavaScript script.
6 * @param callback Optional. A callback function that receives the result of ex\
7 ecution.
8 * If execution fails, the callback function receives the error message\
9 \c EvalScript_ErrMessage.
10 */
11 CSInterface.prototype.evalScript = function(script, callback)
12 {
13 if(callback == null || callback == undefined)
14 {
15 callback = function(result){};
70
Mind you CSInterface is the class, csInterface is the instance of that class: var csInterface = new CSInterface(); - the name is totally
arbitrary, you can call it csi or shantanu if you like it better.
5. CSInterface 35

16 }
17 window.__adobe_cep__.evalScript(script, callback);
18 };

Let’s see how this callback parameter works. Say that your panel needs to know how many
documents are open in Photoshop. In ExtendScript you would:

1 app.documents.length

which returns a number. So you can:

1 var csInterface = new CSInterface();


2 csInterface.evalScript("app.documents.length", function(retVal) {
3 console.log("Number of open documents: " + retVal);
4 });

The callback accepts as a parameter the returned value of the ExtendScript evaluation, so it can log
it. To test this you can use the Chrome Developer Tools console (open Photoshop with the Hello
World panel and visit localhost:8088).

evalScript callback

In case you didn’t know, it’s possible to carriage return in the Console with Alt or Option + Enter.

Synchronous vs. Asynchronous


You might be puzzled by the following code - a slight variation in which the logging is outside the
callback:
5. CSInterface 36

1 var csInterface = new CSInterface();


2 var openDocuments = undefined;
3 csInterface.evalScript("app.documents.length", function(retVal) {
4 openDocuments = retVal;
5 });
6 console.log("Number of open documents: " + openDocuments);

Which logs:

Number of open documents: undefined

Why is that?! We’ve just defined an openDocuments variable, filled with the retVal number in the
callback, logged in the next line. The answer is: because evalScript is asynchronous.
Quoting StackOverflow71 :

“When you execute something synchronously, you wait for it to finish before moving
on to another task. When you execute something asynchronously, you can move on to
another task before it finishes”.

Visually, three tasks might run this way synchronously (top) and asynchronously (bottom):

Synchronous vs. Asynchronous code

Of course the length of each one is proportional to the computational intensity of the corresponding
task (A is something that takes a lot of time, say an AJAX request, B is quicker, etc.) so it’s impossible
to know a priori which one is going to end first.
What happens in the evalScript example above is that the openDocuments variable is declared
and set as undefined. Then csInterface hands the ExtendScript engine the app.documents.length
71
http://stackoverflow.com/questions/748175/asynchronous-vs-synchronous-execution-what-does-it-really-mean
5. CSInterface 37

string to evaluate; but it doesn’t wait for the result, and skips right away to the console.log of the
variable, that is (still) undefined.
So how do you work around this? One way is to keep everything inside the callback, like in the
original example; yet this can easily lead to the so-called “callback hell” (nested callbacks headache):

1 csInterface.evalScript('/* code... */', function(result) {


2 csInterface.evalScript('/* code... */', function (result) {
3 csInterface.evalScript('/* code... */', function (result) {
4 // Gets messy here...
5 });
6 });
7 });

A naif approach is to set a timeout - i.e. wait some predefined amount of time:

1 var csInterface = new CSInterface();


2 var openDocuments = undefined;
3 csInterface.evalScript("app.documents.length", function(retVal) {
4 openDocuments = retVal;
5 });
6 setTimeout(console.log("Number of open documents: " + openDocuments), 500);

Yet there’s a better option: you might want to use Promises72 , which support is provided for instance
by this library called ES6-Promise73 . The code becomes:

1 function evalScript(command) {
2 return new Promise(function(resolve, reject) {
3 csInterface.evalScript(command, resolve);
4 });
5 }
6
7 var csInterface = new CSInterface();
8
9 evalScript('app.documents.length')
10 .then(function(results) {
11 console.log("Number of open documents: " + openDocuments);
12 });

You define an evalScript() method that returns a Promise - way cleaner, in my opinion. In case
you need to chain together evalScript calls, the correct way to structure your code74 passing down
the returned value is as follows:
72
http://www.html5rocks.com/en/tutorials/es6/promises/
73
https://github.com/jakearchibald/es6-promise
74
Thanks to the developer James Stewart for this one.
5. CSInterface 38

1 evalScript('firstJSXFunction()')
2 .then(function(results) {
3 return evalScript('secondJSXFunction()')
4 })
5 .then(function(results) {
6 return evalScript('thirdSXFunction()')
7 });

getSystemPath() and including multiple JSX


In HTML Panels it’s very handy to have access to Folder tokens - that is, named shortcuts to useful
Folder locations. An example of the syntax is:

1 var csInterface = new CSInterface();


2 csInterface.getSystemPath(SystemPath.USER_DATA);
3 // equivalent to:
4 // csInterface.getSystemPath("userData");

A list of the available System Paths is as follows, with the result of the getter in my own computer
on both platforms.

SystemPath.USER_DATA = "userData"

The path to user data


[Mac]: "/Users/davidebarranca/Library/Application Support"
[Win]: "C:/Users/davidebarranca/AppData/Roaming"

SystemPath.COMMON_FILES = "commonFiles"

The path to common files for Adobe applications.


[Mac]: "/Library/Application Support"
[Win]: "C:/Program Files/Common Files"

SystemPath.MY_DOCUMENTS = "myDocuments"

The path to the user’s default document folder.


[Mac]: "/Users/davidebarranca/Documents"
[Win]: "C:/Users/davidebarranca/Documents"

SystemPath.EXTENSION = "extension"

The path to current extension.


[Mac]: "/Users/davidebarranca/Library/Application Support/Adobe/CEP/extensions/HELLOWORLD"
5. CSInterface 39

SystemPath.EXTENSION = "extension"

[Win]:
"C:/Users/davidebarranca/AppData/Roaming/Adobe/CEP/extensions/com.example.helloworld"

SystemPath.HOST_APPLICATION = "hostApplication"

The path to hosting application’s executable.


[Mac]: "/Applications/Adobe Photoshop CC 2017/Adobe Photoshop CC
2017.app/Contents/MacOS/Adobe Photoshop CC 2017"
[Win]: "C:/Program Files/Adobe/Adobe Photoshop CC 2017/Photoshop.exe"

System Paths are particularly useful because, in the context of an HTML Panel (in Photoshop), a
JSX file doesn’t know anymore where it belongs - let me explain. We’re used, in traditional
ExtendScript, to take advantage of the $ helper object to get the location of a JSX file (its path):

1 File($.fileName).path
2 // ~/Desktop

If you attempt to do the same in the JSX of a Photoshop panel you’ll get some really weird result
- for instance alert(File($.fileName)) got me /94 on Mac, and /C/Program Files/Adobe/Adobe
Photoshop CC 2017/25 on Windows, and the path property is equals to "". As a direct consequence,
you can’t expect preprocessor directives such as #include to work in the Panels’ JSX:

1 #include "jsxinc/lib.jsx"
2 // will fail in Photoshop, will work in InDesign

The reason why it fails is: how can the JSX find the jsxinc folder (relative to its own location) if it
can’t find its own path?
Now, according to CEP7 official documentation, the $.fileName fails only if it’s called from the
first loaded JSX (the one in the manifest.xml); you should use CSInterface.evalScript() to
$.evalFile() a second JSX, and finally in that second JSX $.fileName works as expected and you
can do your regular stuff. From my humble point of view the above is laughable, and there is a
quicker way to work around the apparent impossibility to load multiple JSX files.
You need to retrieve in the JS the extension’s absolute path using our friend the getSystemPath()
method, then pass it down to the JSX; that in turn will use it to evaluate a secondary JSX file using
the $.evalFile() function.
5. CSInterface 40

In the main.js

1 var csInterface = new CSInterface();


2
3 // Find the extension's own path
4 var extensionRoot = csInterface.getSystemPath(SystemPath.EXTENSION) + "/jsx/";
5 // "/Users/...blabla.../Adobe/CEP/extensions/com.example.evalJSX/jsx/"
6
7 csInterface.evalScript('evalFile("' + extensionRoot + 'anotherFile.jsx")',
8 function(res) {
9 console.log(res)
10 });

In the photoshop.jsx

1 function evalFile(path) {
2 try {
3 $.evalFile(path);
4 } catch (e) {
5 alert("Exception:" + e);
6 }
7 }

evalFile syntax
Panels are sort of a heap of tangled matters - it’s very difficult to cover one topic
not employing another one that you still have to mention. Namely, I’ve used the
nasty .evalScript('evalFile("' mixed quotes syntax to pass down to the JSX the
extensionRoot variable. This construct is explained in thorough detail in this section of
the next chapter, so have a look at it if you just can’t wait.

Also, you can use a helper function to load any JSX file that belongs to a folder - this way you can
put them all in, say, jsx/includes/:
5. CSInterface 41

Load multiple JSX at once

1 function evalFile(path) {
2 // same as before...
3 }
4
5 function evalFiles(jsxFolderPath) {
6 var folder = new Folder(jsxFolderPath);
7 if (folder.exists) {
8 var jsxFiles = folder.getFiles("*.jsx");
9 for (var i = 0; i < jsxFiles.length; i++) {
10 var jsxFile = jsxFiles[i];
11 try {
12 $.evalFile(jsxFile);
13 } catch (e) {
14 alert(e.message + "\n" + jsxFile);
15 }
16 }
17 }
18 }

Which is called in the JS with:

In the main.js

1 var csInterface = new CSInterface();


2 var extensionRoot = csInterface.getSystemPath(SystemPath.EXTENSION) + "/jsx/";
3 csInterface.evalScript('evalFiles("' + extensionRoot + '")', function(res) {
4 console.log(res)
5 });
5. CSInterface 42

Mind your functions in auxiliary JSX!


Since life is never boring for the Adobe third party developer, you need to know that
there are several ways to write functions that do not work in a secondary JSX (i.e. a JSX
evaluated at runtime using the workaround described above). Both of the following lines
will just fail:
var secondaryFun = function(param) { ... }

function secondaryFun(param) { ... }

… and the reason is that secondaryFun is undefined - don’t ask me why. I’ve logged a bug75
against this behaviour, that by the time you’re reading this might or might not be closed76 .
The only way to build a function in a secondary JSX that sticks in the ExtendScript engine
is omitting the var:
secondaryFun = function(param) { ... }

Since you already are in the global scope there should be no difference - both var
secondaryFun and secondaryFun will become global variables. Polluting the global scope
is another cardinal sin, so you might want to use some JS pattern to keep it as clean as
possible (easiest way is to group everything in an object literal).

75
https://github.com/Adobe-CEP/CEP-Resources/issues/27
76
October 2017, nothing has changed yet.
Enjoyed the content so far?
I’m afraid here ends the free content that I’ve been happy to share with you!
Much more advanced topics, the fully commented code of 28 custom made panels covered in the
book, and three hours of HD video tutorials await you for purchase on h#p://htmlpanelsbook.com

You can subscribe to the newsle#er to get a preview of the video content as well (half of an hour, for
free) - no spam involved.

Feel free to get in touch if you want - in the Course homepage you can find email, socials, etc.
!ank you and kind regards from Italy!

Davide Barranca

The Full Package is available HERE!


Acknowledgements
The idea of writing this book didn’t strike me until I read ProgWriter³¹⁹ by Azat Mardan, so he’s
definitely the one I should thank first. Without his input I would have sticked to few, scattered
blogposts, instead of embarking on this long journey: which, frankly, has made me learning more
that I initially would have supposed.
I owe a lot to many people from Adobe: over time I’ve proved to be a pest with my questions,
feature requests and bug submissions - despite that, they’ve always been supportive and listening to
my thoughts. Engineers who actually build the products we’re using, care as much as we do about
them - when I’ve moved criticisms (and I did) it wasn’t toward them: they’re not the ones who
decide whether to invest time and resources on a particular project. Each and every one of them has
been of great help: I’d like to thank Tom Ruark, Jeffrey Tranberry and Eric Ching; Arthur Guo Wei,
Hui Ding and Lea Savage; Hallgrimur Bjornsson and Jonathan Ferman; Krystal Woods and Fraser
Gregor. Thank you all.
The developers’ community of HTML Panels isn’t huge (yet!); I’ve exchanged thoughts and received
a great deal of help and friendly support from many people involved in the challenging business of
building and marketing extensions, and/or in the Scripting community. I’d like to mention and thank
for their precious time Chris Russ, Cameron McEfee, Matias Kiviniemi, Sandra Voelker, Anastasiy
Safari, Olav Kvern, Gabe Harbs, Marc Autret, Loic Aigon, Peter Kahrel, Kris Coppieters, Norm
Sheeran, Greg Benz, Franz Hoffman, Joel Galleran, James Stewart, Max Penson, Chuck Uebele,
Michel Mariani, Marek Hrabe, Sergey Kritskiy, Kamil Khadeyev, Anton Lyubushkin, Trevor Morris,
Christoph Pfaffenbichler. A special thank to xbytor from the PS Scripting community.
Giuliana Abbiati (aka Cromaline), has been my Panels’ alter ego: without her support, sincere
friendship and truckloads of chocolate I wouldn’t have accomplished the half of this. Thank you.
Last but not least, I owe to my wife Elena not only all the time this book has stolen to our marriage
in the last 7 months, but much more, for she took care of everything I’ve neglected - without her
love and support none of what I’ve done in the last 16 years would have been possible. Included
our daughter Anita, who - I hope - will remember dad constantly grumbling and cursing at some
broken code as a lesson on persistence.
Thank you too, reader - and please: get involved, participate, be vocal (also with Adobe!) Let’s
make the HTML Panels community stronger and wider, which is the only way to keep this business
profitable, long lasting and fun.
³¹⁹http://progwriter.com/

268
Copyright
© 2016 Davide Barranca
Adobe® Photoshop® and Adobe® Creative Cloud® are registered trademarks of Adobe Systems
Incorporated in the United States and/or other countries. All other trademarks are the property of
their respective owners.
THIS PRODUCT IS NOT ENDORSED OR SPONSORED BY ADOBE SYSTEMS INCORPORATED,
PUBLISHER OF ADOBE PHOTOSHOP AND THE ADOBE CREATIVE CLOUD.

This book was made using Leanpub. Leanpub empowers authors and publishers with the Lean
Publishing process. Lean Publishing is the act of publishing an in-progress ebook using lightweight
tools and many iterations to get reader feedback, pivot until you have the right book and build
traction once you do.
I’d like to thank their team for the support, professionality and care - I couldn’t recommend them
more if you’re interested in producing your own book.

269

Vous aimerez peut-être aussi