Connecting to Photoshop with Flash, Flex, and AIR

Introduction

Guest Author

This is a guest post by Daniel Koestler, an Adobe applications developer. This post will explain how to connect your Flash, Flex, and AIR apps to Photoshop using the Photoshop Touch SDK. The author created the Photoshop Touch SDK for AS3 with help from Renaun Erickson, an Adobe developer evangelist. This part of the SDK is a SWC distributed in the freely available download.

This article will tell you how to create a new project, connect to Photoshop, and send simple commands back and forth. There are additional resources at the end of the article, which will guide you through more advanced steps.

What is the Photoshop Touch SDK?

Adobe Nav uses the Photoshop Touch SDK

Adobe Nav uses the Photoshop Touch SDK

The Photoshop Touch SDK is a collection of APIs that allow virtually any device to connect to and control Photoshop, using any Internet or WiFi connection. For the first time, you can interface with Photoshop directly, and use this to create mobile, desktop, or web applications that are tailored to the needs of creative professionals or casual-creative users.

The Photoshop Touch SDK is available for free from Adobe, and works with Photoshop CS5 12.0.4 and above. It also includes a SWC library, which contain the APIs that this article covers. This SWC library, called the Photoshop Touch SDK for AS3, allows you to write very simple ActionScript 3 code in any Flash, AIR, or Flex application, and saves you from doing tedious socket-level work. As you’ll hopefully discover, these AS3 APIs are flexible and easy-to-use, and will allow you to leverage the portability of Flash, versatility of Flex, and power of ActionScript 3 to help you realize your vision for designing creative apps.

Sample Code

As you follow along, you may want to refer to the sample code, which contains a project that’s been created by following this blog post. See the Additional Resources section for information about an upcoming ADC article, which will also cover more advanced topics.


Table of Contents:

Introduction
Requirements

Creating a Project
Connecting to Photoshop
Sending Commands to Photoshop
Summary
Additional Resources


Requirements

Software

  • Photoshop CS 5 12.0.4 or later (update CS 5 from within Photoshop)
  • Flash Builder 4.5 (or an IDE of your choice) with the Flex 4.5 SDK

Libraries


Creating a Project

Step 1: Create a new Flex Mobile Project in Flash Builder

The first step is to create a new Flex mobile project. Although we’re using Flex, the Flash runtime runs on a variety of platforms and devices, so you could just as easily create an AS3 or AIR project. For this article, though, we’ll focus on creating a mobile Flex app.

  1. Open Flash Builder and go to File -> New. Select Flex Mobile Project.
  2. Enter a project name, and choose a location. Click next.
  3. Make sure Google Android is your target platform, and select “View-Based application.”
  4. Name your initial view “LoginView.” It’s here that you’ll write code to handle the connection to Photoshop.
  5. Click finish to complete the new Flex mobile project.

Step 2: Link to the Photoshop Touch SDK library

The Photoshop Touch SDK includes a file called PhotoshopTouchSDK.swc. This is a pre-compiled library that you can integrate into any Flash or Flex applications, which provides APIs to connect to and control Photoshop. This part of the library is open source, and you are free to modify and learn from the code (in accordance with the accompanying EULA and/or license agreement).

When you downloaded and extracted the Photoshop Touch SDK from the Adobe site (http://www.adobe.com/devnet/photoshop.html), it will have created the PhotoshopTouchSDK.swc file in the following relative location:

(some directory)\samples\air\photoshoptouchsdk\bin\PhotoshopTouchSDK.swc

  1. Locate the PhotoshopTouchSDK.swc file in the extracted files.
  2. Copy PhotoshopTouchSDK.swc and paste it in the “libs” folder inside your project directory. You can do this from within Flash Builder, or using Explorer/Finder/bash/etc.

Step 3: Link to the other required libraries

The file (some directory)\samples\air\photoshoptouchsdk\README.txt will indicate the complete list of libraries that are necessary to use the APIs. At the time of this writing, there are three additional libraries you have to include:

  • as3corelib (https://github.com/mikechambers/as3corelib)
  • as3crypto (https://code.google.com/p/as3crypto/)
  • StructuredLogTestingSDK (for logging) (https://code.google.com/p/structuredlogtesting/)

Obtaining these libraries is relatively straight-forward. Follow the included links (or use Google). At the time of this writing, you can take the following steps on the libraries’ respective sites:

  • Click the grey “Downloads” button for as3corelib and obtain “as3corelib-.93.zip.” Extract this and open “lib,” and you’ll see the as3corelib.swc file.
  • For as3crypto, click the “Downloads” link and obtain “as3crypto.swc.”
  • For StructuredLogTestingSDK, click the “Downloads” link and get “StructuredLogTestingSDK-1.3.swc.”

Take these three SWCs and drop them into the “libs” directory in your project, as you did with the PhotoshopTouchSDK SWC.

Your project should link to these four libraries

Your project should link to these four libraries


Connecting to Photoshop

Overview

The PhotoshopTouchSDK includes a class called PhotoshopConnection, which provides functions and dispatches events for managing the connection state with Photoshop. You’ll need to call functions such as connect(), initEncryption(), and (to save time for future connections) initEncryptionFromKey(). You’ll need to listen for PhotoshopEvents such as PhotoshopEvent.CONNECTED, ENCRYPTION_SUCCESS, and ERROR.

Connecting to Photoshop using this class is a three step process, barring any communication or password problems:

  1. Create a new PhotoshopConnection and listen for events
  2. Call connect() on your instance of the PhotoshopConnection
  3. After a successful connection, initialize encryption using either initEncryption() or (if you’ve saved the user’s key with getKey()), initEncryptionFromKey()

After these steps have been completed, you may send and receive data with Photoshop. As we code these features into the mobile application, we’ll create data structures that will allow you to easily add functionality later in this article.

Step 1: Create a singleton Model, to establish a MVC design

Our application needs to create a PhotoshopConnection, but we want to store it in a location where it can be conveniently accessed by various parts of our UI (the View in the Model-View-Controller design pattern). Thus, we’ll create a Model in which to store Object references, constants, and variables.

  1. Right click your project in Flash Builder, and choose New ActionScript Class
  2. Enter the string “model” as the package
  3. Name the Class “Model
  4. Click Finish

We now need to add a static variable to this class, a function called getInstance() which returns that variable, and, finally, a Bindable, public variable that will store our PhotoshopConnection. Enter the following code inside of public class Model { ... }


private static var _inst:Model;
		
[Bindable] public var photoshopConn:PhotoshopConnection;
		
public function Model()
{

}
		
public static function getInstance():Model
{
    if ( !_inst )
    {
        _inst = new Model();				
    }
    return _inst;	
}

We can now reference the variable photoshopConn from either AS3 or Flex code, simply by calling Model.getInstance() and referencing photoshopConn. I.e., Model.getInstance().photoshopConn.

Step 2: Instantiate the PhotoshopConnection and listen for events

We’ll instantiate the PhotoshopConnection the first time the user attempts to connect, but it would be a good idea to create initialization code in your own applications, to handle things like reading the hostname and password from disk, managing the user’s key and preferences, etc.

Open your views/LoginView.mxml file. We’ll allow the user to connect to Photoshop using a Spark Button, and they’ll have to enter the hostname and password using s:TextInput components. Type the following into the DisplayList on your LoginView Class:


<fx:Script>
        <![CDATA[
            protected function loginButton_clickHandler(event:MouseEvent):void
            {
                    // TODO Auto-generated method stub
            }
        ]]>
    </fx:Script>
	
    <s:VGroup width="100%" height="100%">
        <s:Label text="Hostname"/>
        <s:TextInput id="hostname" text="192.168.1.10"/>
        <s:Label text="Password"/>
        <s:TextInput id="password" displayAsPassword="true" text="photoshop"/>
        <s:Button id="loginButton" label="Login" click="loginButton_clickHandler(event)"/>
    </s:VGroup>
</fx:Script>

You’ll see that we’ve created two TextInput components and a Button, as well as an fx:Script tag that will contain some click-handler logic. When this button is pressed, we want to create a new PhotoshopConnection, and listen for events. Thus, type the following, so that your fx:Script tag looks like this:


<fx:Script>
    <![CDATA[
        import com.adobe.photoshop.connection.PhotoshopConnection;
			
        import model.Model;

        protected function loginButton_clickHandler(event:MouseEvent):void
        {
            if ( !Model.getInstance().photoshopConn )
            {
                createNewConnection();
            }
        }
			
        private function createNewConnection():void
        {
            var m:Model = Model.getInstance();
            m.photoshopConn = new PhotoshopConnection();				 
        }
     ]]>
</fx:Script>

We’ve created a function called createNewConnection(), which is called if the photoshopConn variable is null. We now have to attach event listeners to this new PhotoshopConnection. Add the following to the bottom of your createNewConnection function:


m.photoshopConn.addEventListener(PhotoshopEvent.CONNECTED,onConnected);		 
m.photoshopConn.addEventListener(PhotoshopEvent.ENCRYPTION_SUCCESS,onEncrypted);
m.photoshopConn.addEventListener(PhotoshopEvent.ERROR,onError);

Of course, we now have to create the functions onConnected, onEncrypted, and onError, in which we’ll put the application logic for handling these eventualities.


private function onConnected(pe:PhotoshopEvent):void
{
    trace("Connected established.");
}
			
private function onEncrypted(pe:PhotoshopEvent):void
{
    trace("Encryption was successful");
}
			
private function onError(pe:PhotoshopEvent):void
{
    trace("There was an error while connecting!");
}

With these functions created, we’re ready to try and connect to Photoshop. It’s always a good idea to remove event listeners when you’re not using them, however, so create a function called cleanUp(), and remove each of those three event listeners from the photoshopConn instance. We’ll call this function once we’re ready to switch Views in the application (after successfully encrypting the connection).

Step 3: Call connect()

As you’ll see, connecting to Photoshop is very simple. In your click handler function for the “Login” button, add the following code to the bottom of the function:


    Model.getInstance().photoshopConn.connect(this.hostname.text);

As the asdocs for the connect() function note: </p.

Opens a Photoshop data connection to Photoshop.
You may call this function before you call initEncryption(), but you will have to initialize the encryption before you can successfully communicate with Photoshop.

Parameters
serverName:String – IP address or resolvable hostname of the server

serverPort:int (default = 49494) – Port to connect to. Default is 49494

After this function has been called, the API will attempt to connect. It will dispatch the necessary events during this process.

Step 4: Initialize encryption, and move on to the next View.

As the docs indicate, a successful connection will cause PhotoshopConnection to dispatch a PhotoshopEvent.CONNECTED event. Since we’re listening for this event, our function onConnected will be called. It’s here that we’ll make the call to initialize encryption. Thus, make your onConnected() function look like the following:


private function onConnected(pe:PhotoshopEvent):void
{
    trace("Connected established. Encrypting connection. This will take a few seconds...");
    Model.getInstance().photoshopConn.initEncryption(this.password.text);
}

If this is successful, our code will enter the onEncrypted() event handler. At that point, we’re ready to send data to and from Photoshop. To prepare for this step:

  1. Right click your project and select New MXML Component
  2. Put it in the package “views,” and name it “HomeView
  3. Click “Finish”

Now, we just have to push a HomeView onto the ViewNavigator:


private function onEncrypted(pe:PhotoshopEvent):void
{
    trace("Encryption was successful. Cleaning up event listeners.");
    this.cleanUp();
    trace("Proceeding to the 'Home' View.");
    this.navigator.pushView(HomeView);
}

We’ve also cleaned up the event listeners, which you should do wherever possible to prevent memory leaks. You should now test your project. In the next section, we’ll send some simple commands to Photoshop.


Sending Commands to Photoshop

At this point in your application, you’ve used the Photoshop Touch SDK to establish an encrypted connection to Photoshop. You’re ready to send and receive data. With a single function call, you can push raw bytes to Photoshop, and—if you wish—you could create your own datagram format that encapsulates these bytes. The Photoshop Touch SDK includes ActionScript APIs to do this for you, however, and provides functions which minimize the amount of low-level code you have to write.

The first of these classes is the MessageDispatcher. As the asdocs state:

The MessageDispatcher is an abstraction layer on top of the PhotoshopConnection, which makes it easy to send properly formatted messages to Photoshop. You can either call some of the helper functions that will create and dispatch the messages for you (createNewDocument, requestThumbnail, etc.), or create your own IMessage and call sendMessage().

Since we’re just beginning, we will indeed use the simplest of these method calls. We’ll create an s:Button in our HomeView that tells Photoshop to create a new document. Photoshop will respond with an id referencing the document.

Step 1: Create a MessageDispatcher instance

Before we can use the MessageDispatcher, we have to create a new instance of it, and give it a reference to our existing PhotoshopConnection (this allows the MessageDispatcher to use the connection that we initialized in the previous section). We’ll store this instance in the Model, just like we do with the photoshopConn variable. Thus, in your Model.mxml file, add the following:


[Bindable] public var messageDisp:MessageDispatcher;

The Bindable property allows us to use this variable in Flex and/or attach our own ChangeWatchers, should the need arise.

We now have to instantiate this variable. Open your HomeView Class and generate an event handler for the initialize event. Type the following:


protected function view1_initializeHandler(event:FlexEvent):void
{
    var m:Model = Model.getInstance();
    if ( !m.messageDisp )
    {
        m.messageDisp = new MessageDispatcher(m.photoshopConn);
    }
}

As you can see, this code will only create a MessageDispatcher should it not already exist, and it’ll pass a reference to the existing PhotoshopConnection. You’ll want to handle initialization logic like this in a dedicated initialization controller, should you be creating a more robust application. We’re now ready to use this Object.

Step 2: Listen for Photoshop’s Response(s)

We could send the command at this point, but, should an error occur, our application would never hear about it. Thus, it’s necessary to attach some event listeners to the PhotoshopConnection. There are three events that are particularly useful for handling message-related communication:

  • ErrorEvent: Dispatched when there’s been an error in either data transfer, encryption, or connection management.
  • ErrorMessageReceivedEvent: Dispatched when an error message is received from Photoshop.
  • MessageReceivedEvent: Dispatched when a message is received from Photoshop.

There are a number of other useful events, such as MessageSentEvent, ProgressEvent, and ImageReceivedEvent, but we won’t be using them for this example.

Inside of your HomeView initialization handler, add the following to attach event listeners to the PhotoshopConnection:

			
m.photoshopConn.addEventListener(PhotoshopEvent.ERROR,onError);
m.photoshopConn.addEventListener(PhotoshopMessageEvent.MESSAGE_RECEIVED,onMessage);
m.photoshopConn.addEventListener(PhotoshopMessageEvent.ERROR_MESSAGE_RECEIVED,onErrorMessage);

Of course, you now have to create three functions: onError, onMessage, and onErrorMessage:


private function onError(pe:PhotoshopEvent):void
{
    trace("Error while sending a message!");
}

private function onMessage(pme:PhotoshopMessageEvent):void
{
    trace("We received a message from Photoshop");
}

private function onErrorMessage(pme:PhotoshopMessageEvent):void
{
    trace("We received an error message from Photoshop");
}

As before, it’s a good idea to clean up event listeners that you no longer need. So create a cleanUp() function that calls removeEventListener for those three events.

Step 3: Send a Message to Photoshop

We’re finally ready to make Photoshop do something! We’ll ask it to do something simple: create a new document. If this is successful, Photoshop will send a message in response that contains the id of the created document.

First, use MXML to create a Spark Button inside of the DisplayList:


<s:Button id="createNewDocument" label="Create a New Document" click="createNewDocument_clickHandler(event)"/>

Inside of the click handler for this Button, we’ll tell the MessageDispatcher to dispatch a Message to Photoshop.


Model.getInstance().messageDisp.createNewDocument();

Pay particular attention to the default parameters in that function call. As the ASDocs say:

Dispatches a message instructing Photoshop to create a new document with the specified parameters.

Parameters
transactionID:int (default = -1) – You can override the default value if you wish to send the message with a custom transactionID.
If you leave it as -1, the message dispatcher will keep track of transactionIDs for you.
It’s recommended that you don’t mix these two systems, as it might lead to conflicts and unpredictable behavior.

width:int (default = 640) – The width of the document to create, in pixels

height:int (default = 480) – The height of the document to create, in pixels

ppi:int (default = 72) – The density of the document to create, in pixels per inch

Since we’re creating a relatively simply application, we don’t need the added flexibility that comes with managing our own transaction IDs. We’ve also accepted the default values for the width, height, and PPI of the document that’s to be created.

You should run your application. Once you press the button, you should see the appropriate trace statements, and Photoshop will create the document. In my case, Photoshop responded with a TextMessage. By inspecting the pme.message.message field, I was able to see that Photoshop responded with “[Document Untitled-1]“–the ID of the document.

To finish this step, you should add an event listener for the “removing” event to the View; inside of the handler, call this.cleanUp(), to remove the event listeners that we no longer need.


Summary

At this point you’ve been shown how to: create a project; link to the Photoshop Touch SDK libraries; set up a Model-View architecture for managing the Photoshop objects; connect to Photoshop and manage encryption; and send messages while listening for responses.

There are still a number of tasks that you may want your application to perform, and the SDK can help you with these. For example, you can use the SDK to:

  • Listen for foreground and background color changes
  • Listen for tool change events
  • Be notified when the user modifies a document
  • Change the brush size, the currently selected tool, or the document’s properties
  • Send other, custom commands

These tasks are made possible by using the SubscriptionManager, TransactionManager and Photoshop’s ScriptListener plug-in. Please see Daniel Koestler’s ADC article and blog to learn about these tasks, and to get tutorials and sample code that’ll help you take your applications further.


Additional Resources

An ADC article covering the content of this blog post (as well as more advanced topics) will be available next week. Please check Daniel Koestler’s blog http://blogs.adobe.com/koestler, where he’ll post the article as soon as it’s available. You may also want to follow him on Twitter: @antiChipotle.

Update 6/16/2011: The ADC Article is now published. That article contains some additional information about using the Photoshop Touch SDK.

You may want to download the sample code, which contains a project that has been created following the above steps. The ADC article contains code that demonstrates the SubscriptionManager, custom messages, and other, more advanced tasks.

15 Responses to Connecting to Photoshop with Flash, Flex, and AIR

  1. James says:

    Very useful article… Thanks

    Question: How can I discover available Photoshop connections? Rather than providing an IP address to connect to that computer, I want to see all the available Photoshop connections to connect with. Like you guys have done with these three apps (Eazel, Color Lava, Nav).

  2. YopSolo says:

    Sounds cool but i got this.

    [IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2031: Socket Error. URL: xxx.xxx.x.xx" errorID=2031]

    (i am using the photoshop CS5 12.1 trial)

    • dkoestle says:

      At what point do you get that event? When you attempt to connect, or when you attempt to send a command?

  3. YopSolo says:

    login attempt

    ***
    private function onError(pe:PhotoshopEvent):void
    {
    trace( pe.data );
    trace(“There was an error while connecting!”);
    }
    ***
    [SWF] ADCTutorial.swf – 3 354 931 octets après la décompression
    [IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2031: Socket Error. URL: xxx.xx.x.xx" errorID=2031]
    There was an error while connecting!
    ***

    • dkoestle says:

      There could be a number of things causing that IOErrorEvent, so we need more information. The Photoshop Touch SDK uses the StructuredLogTestingSDK for its internal logging. We can turn it on and see some information that’ll help you debug.

      You first have to set up a trace target, to have the SDK log via trace statements:

      var traceTarget:TraceTarget = new TraceTarget();
      traceTarget.includeCategory = true;
      traceTarget.includeDate = true;
      traceTarget.includeLevel = true;
      traceTarget.includeTime = true;

      Then call two static functions on SLog; the first function will add the trace target, and the second will test the logger’s ability to output:

      SLog.addTarget(traceTarget);
      SLog.debug(this,"Logging initialized.");

      You may have to link to StructureLogTestingSDK.swc. You can get it here: https://code.google.com/p/structuredlogtesting/downloads/list
      If that link stops working, its homepage is: http://structuredlogs.com/

  4. Pingback: John Nack on Adobe : News for Suite developers

  5. JohnC says:

    I’m always getting error 2031 when trying to connect to any socket from Flex Mobile projects, I tried to serve crossdomain.xml, security policy files – no luck. Sockets are broken in Flex Mobile, I gave up.

    • Daniel Koestler says:

      Hey John,

      Would you be able to provide me with a project where you keep getting #2031? crossdomain.xml and policy files shouldn’t be necessary, though it’s possible you’re trying to connect in a way I didn’t anticipate.

      (Did you try the usual things, such as switching networks, disabling firewalls, manually verifying the IP, etc?)

      -Dan

  6. Travis Estep says:

    The reason for the error #2031 is the lack of enabling Photoshop to accept incoming credentials and failing to set a password. To correct this issue, you must edit your Photoshop settings.

    To allow remote connections:

    Open Photoshop.
    Choose the Edit menu.
    Choose the “Remote Connections…” option.
    You may leave the Service Name as is, or you can specify a different one.
    Enter a password, at least 6 characters in length.
    Check the box to “Enable Remote Connections”.
    Click OK.

    Now when you run the AIR app from this tutorial, your app will be able to connect to Photoshop, properly authenticate, and communicate.

    • Travis Estep says:

      Also, be sure to enter your correct password in the Login window in this app when you run it. Alternatively, you can also edit the source to pre-populate your password by changing the text value of the text input field.

  7. Jed says:

    Hello, I want to know how to send a Image to the Photoshop? Because I had send an Image to the Photoshop, but I don’t know how to let the Photoshop to open this Image.I don’t
    know Where can I find this Image.

    If you can give me an example, it’s best!

    Thank you!

    • petegreen says:

      If you have Photoshop installed on your system, you can use File > Open from within Photoshop and navigate to your image files to open them.

      If you’re on a Mac, then you can also drag an image to the Photoshop icon on your Dock

      On Windows 7, you can rightclick an image and choose “Open With > Adobe Photoshop CS6″

  8. Daniel says:

    Hi. One of my computers is not showing the IPv4 address inside Photoshop (office network). Any reason for that? I can’t connect with a prototype I’m working on.

    Another question, there is any way to get a list of a discovered connections? You know, some applications like Acquire do this.

    Thanks!