Getting started with PS CS4 Panels.. need some help

General Discussion of Scripting for Flex, Flash & CS SDK

Moderators: Tom, Kukurykus

renderhjs

Getting started with PS CS4 Panels.. need some help

Post by renderhjs »

I am stuck with my first Photoshop CS4 panel


I am getting a NULL object from the "CSXSInterface.instance" singleton. And this happens booth if I run the compiled SWF file in the debug standalone flash player and within Photoshop CS4 as a panel. Obviously the "CSXSInterface.instance" is important to communicate within Photoshop between JSX and AS3.

So I was hoping that you guys could clarify for me what I really need in order to develop SWF panels (just pure AS3, no flex). This is what I use at the moment:
  • FlexSDK (3.5.0) & FlashDevelop (3.1.0 RTM) (my usual coding environment)
  • Photoshop v11.0 (CS4)
  • CSXSLibrary-2.0-sdk-3.4.swc (but same issue with CSXSLibrary-2.0-sdk-3.3.swc)
I followed a few tutorials all guiding me more or less through the same:
http://scriptplayground.com/tutorials/a ... Flash-CS4/ ... Flash-CS4/
http://www.adobe.com/devnet/photoshop/s ... l#csxsfile ... l#csxsfile

which is more or less including the SWC library and putting the compiled SWF in the \Plug-ins\Panels\ folder. But even with this simplified class and sample code I get a NULL object for the instance() singleton.
Code: Select allpackage
{
     import com.adobe.csxs.types.*;
     import com.adobe.csxs.events.*;
     import com.adobe.csxs.core.CSXSInterface;
     import flash.display.Sprite;
     import flash.events.Event;
     
     public class Main extends Sprite
     {   
          public function Main():void
          {
               if (stage) init();
               else addEventListener(Event.ADDED_TO_STAGE, init);
          }
          private function init(e:Event = null):void {
               CSXSInterface.instance.addEventListener(StateChangeEvent.WINDOW_OPEN, creationComplete);
          }
          private function creationComplete(e:Event):void {
               
          }
     }
}
Would it succeed (according to some tutorials) it would call the creationComplete method. But even on triggered buttons so non loading and initialization triggered events I get a NULL object for the CSXSInterface.instance.

So...
If I need a older SWC library could someone send me one that works, or if there is something else to watch out please tell me. Also I explained the problem on the Adobe forums as well but they seem to be rather CS5 focused
http://forums.adobe.com/thread/710795
There might be some other bits to read from my question there. Hopefully I can start soon scripting for PS CS4 - as I have a lot of productive ideas that I want to develop.

thanks in advance,

Hendrik
renderhjs

Getting started with PS CS4 Panels.. need some help

Post by renderhjs »

I finally found a older SWC library ("CSXSLibrary.swc") at:
http://wwwmacr-sjc0.adobe.com/devnet/ph ... ripts.html ... ripts.html
within the ZIP:
http://download.macromedia.com/pub/deve ... cripts.zip ... cripts.zip

And my panel seems to finally work with that under Photoshop CS4 which is awesome .I just wish Adobe would be more clear on this whole Panel SWF extending stuff. Its really tricky to get your hands on the CSXSLibrary.swc file for CS4 or any of the older ones.
Mike Hale

Getting started with PS CS4 Panels.. need some help

Post by Mike Hale »

Just some notes.

The new CSXSLib does work with CS4/CS5 using Flex/Flash Builder and the Photoshop Panel Guide.

The CS IDE ( the Adobe forum you linked ) is a way of creating single/cross app CS5 panels only.

I could never get the example at scriptplayground to work even with the older lib.

I think Adobe is unclear about panels because they have( or at least had ) several different teams working on different approaches. I think Patch Panel/Swichboard has been merged into CS IDE.

Please feel free to post some examples here for other users like yourself that don't want to use Flex/Flash Builder when creating panels for CS4.
renderhjs

Getting started with PS CS4 Panels.. need some help

Post by renderhjs »

sure thing, I got everything working the way I wanted it in the first place.

This soloution works with any flash environment including:
-Flash CS3/CS4 IDE
-FlexSDK
-Flex
-FlashBuilder
-FDT,..

And with the Photoshop CS4 64bit (haven't tested on CS5 or 32bit but I assume it works as well?). In my Photoshop CS4/Plug-ins/Panels I have 2 files a JSX (Javascript) and compiled AS3 SWF file (booth need to have the same filename):



----The JSX file----
contains:
Code: Select allfunction evalualte_script( scriptVariable )
{
   try{
      return eval( "{"+unescape( scriptVariable ) +"}"  );
   }catch( e ){
      alert( "Error (" + e.num + ") in file '" + e.fileName + "', line " +  e.line + ":\n" + e.message );
   }
}I basically evaluates passed through scripts that are send from within Flash or AS3. This gives me complete freedom as I can construct, parse or load in scripts within AS3 and then execute them there.


----The SWF file----
In order to call the JSX evaluate_script you need the CSXSLibrary.swc which can be found in this zip:
http://download.macromedia.com/pub/deve ... cripts.zip ... cripts.zip
or now on my server (because it was hard enough to find it in the first place, and just to be sure):
http://www.renderhjs.net/bbs/ps-scripts/CSXSLibrary.swc

Next that SWC library needs to be embedded (different in any editor)
I use flashdevelop so its just a matter of copying the SWC somewhere in my project folder and then rightclick (within FlashDevelop) and say "Add to Library". For Flash CS3/CS4,.. you can embed it under Publish Settings > Script Settings > External Library Path > and then browse via the Browse for SWC icon.

In the sourcecode you need to import the CSXSInterface class using:
Code: Select allimport com.adobe.csxs.core.CSXSInterface;

from there on you can evaluate any JSX scripts for PS using:
Code: Select allCSXSInterface.instance.evalScript("evalualte_script",escape("alert('Hello World'"));
because the CSXSInterface seems to use some AMF or alike bridge communication characters with spaces, returns, tabs and alike can't be send. Which is why I use escape() within AS3 which converts it into a simple string without special characters. The JSX evaluate_script then on the other hand unescapes() the recieved string back to its original string and then evaluates (executes) the string as a JSX script.




----Color setting example----
Here is another example in AS3 to for example set Photoshop foreground color to a random hexadecimal color:
Code: Select allvar color:String = int(Math.random() * 0xffffff).toString(16);
var script:String = "var sColor =  new SolidColor;\n";
script +="sColor.rgb.hexValue = '"+color+"';\n";
script += "app.foregroundColor = sColor;\n";
CSXSInterface.instance.evalScript("evalualte_script",escape(script));
this example converts a int color value in AS3 to string hexadecimal and then again converts it within a JSX script to a solidColor object which Photoshop expects to recieve.


----JSX embedding----
embedding scripts as its described here:
http://www.adobe.com/devnet/photoshop/a ... ripts.html ... ripts.html
works with this method as well. It would look something like this:
Code: Select all[Embed(source="js/HolaWorld.js",mimeType="application/octet-stream")]
private static var HolaWorldJS: Class;
//somewhere further in the body of the script, like a button event:
CSXSInterface.instance.evalScript("evalualte_script",escape(new HolaWorldJS().toString()));


hope this helps some people, as it took me 2 days to get to this point because the official documentations are just to scattered.
izo

Getting started with PS CS4 Panels.. need some help

Post by izo »

thanks a lot man, since many day i try to do that.
i never see a thing like that... whats adobe doing... ?

the sample script execute a all the jsx file, do you now how to execute a function from a jsx file ?
renderhjs

Getting started with PS CS4 Panels.. need some help

Post by renderhjs »

just to clarify: Do you mean any external JSX file or actually within the one with the same filename as the SWF file?

Because I think at this point that you can only communicate with the one JSX file with the same name. So in my example of the 2 files I had:

I think you can only access functions within the "PSPanel.jsx" file.

But say for example your JSX file is a bit extend from my first example and also holds the following additional function:
Code: Select allfunction evalualte_script( scriptVariable ){
   try{
      return eval( "{"+unescape( scriptVariable ) +"}"  );
   }catch( e ){
      alert( "Error (" + e.num + ") in file '" + e.fileName + "', line " +  e.line + ":\n" + e.message );
   }
}
function helloWorldFunction(parameter){
   alert("AS3 called this JSX function with the variable: "+parameter);
}So in this example you have another function within that JSX file that accepts 1 parameter.

From what I tested there are 2 ways now to call that function from within Flash or the SWF panel.
1.)The way I do it:
Code: Select allCSXSInterface.instance.evalScript("evalualte_script",escape("helloWorldFunction('Hana Bi')"));
This is kind of double you might say because we are not directly calling the helloWorldFunction function but instead have it loop through that evaluate_script. So why would I do that?
Which brings me to the other way of doing it but which has its flaws:


2.) the way the API expects you to do it:
Code: Select allCSXSInterface.instance.evalScript("helloWorldFunction","Hana B");
This looks easier and straight forward but the reason I came up with the first one using the eval stuff is because as soon as you pass on any parameters with other values than simple strings, or strings with spaces or special characters (tab, return, space,...) it just doesn't call the JS functions or script at all- it just mutes or ignores it.
This is because they or maybe it was intended, but at least things are not getting escaped and unescaped within the API. If you are not familiar with it it basically is a way to wrap advanced characters with a limited character set and then decode it back to its original state once its send through. Have a look at this: http://www.theukwebdesigncompany.com/ar ... acters.php ... acters.php and you might recognize some of it as its used in many web services. I don't know why they did it the way they did but I certainly recognize it from AMFphp and similar things.
So to sum this one up:
Code: Select allCSXSInterface.instance.evalScript("helloWorldFunction","Hana Bi"); doesn't work (at least not in my tests), so does
Code: Select allCSXSInterface.instance.evalScript("helloWorldFunction",97.05);
however:
Code: Select allCSXSInterface.instance.evalScript("helloWorldFunction","HanaBi");works as it doesn't contain any spaces in the parameter nor special characters or special objects instead of a string.

So in order to still pass through numbers, hex values, objects, arrays and many other objects from AS3 to the JSX level I just wrap the things I want to call or evalualte in strings and send it to the evaulate script which unescapes it back to its original string case and executes it as JS code at the JSX level.

I hope that I make sense to you, if not just bump here with a example of what you want (i.e. execute this function in this file from this place in flash...). Also my examples are really bare bone, I actually already wrote a wrapper class myself to simplify these things a little bit. But the first step is always to just make it work and then go fancy ways

Hendrik
izo

Getting started with PS CS4 Panels.. need some help

Post by izo »

i try but nothing happen :

here my code :
mxml :

Code: Select all   [Embed(source="GrfsTools.jsx",mimeType="application/octet-stream")]
         private static var HolaWorldJS : Class;         
         
         public function onCreationComplete():void{
            var myString: String = new HolaWorldJS().toString();
            CSXSInterface.instance.evalScript("test","hello");
}


and jsx

Code: Select allfunction test(toto) {
alert(toto);
}
renderhjs

Getting started with PS CS4 Panels.. need some help

Post by renderhjs »

this is odd, but it seems that the event:
Code: Select allCSXSInterface.instance.addEventListener(StateChangeEvent.WINDOW_OPEN,...)
Code execution works however if you click on buttons or events that are triggered when the SWF panel is initialized in PS for sure. Alternatively if you really need to fire a JSX script at launch you could add a timer within AS3 that triggers after lets say 200-300 ms once the SWF panel is loaded.
Also try a few of these just in case (taken from: http://blogs.adobe.com/cssdk/2010/08/ma ... nel-2.html ... nel-2.html):
var myCSXS:CSXSInterface = CSXSInterface.getInstance();
myCSXS.addEventListener("documentAfterActivate", myEventHandler);
myCSXS.addEventListener("documentAfterDeactivate", myEventHandler);
myCSXS.addEventListener("applicationActivate", myEventHandler);
myCSXS.addEventListener(StateChangeEvent.WINDOW_OPEN, myEventHandler);
myCSXS.addEventListener(StateChangeEvent.WINDOW_SHOW, myEventHandler);

I created a small test ZIP which works with just 1 class that creates a textfield and a simple button that can call your JSX function within the JSX file:
http://www.renderhjs.net/bbs/ps-scripts ... elTest.zip
The Photoshop files are located in the bin folder, src contains the SWC library and the simple class:
Code: Select allpackage
{
   import com.adobe.csxs.core.CSXSInterface;
   import com.adobe.csxs.events.StateChangeEvent;
   import flash.display.Sprite;
   import flash.events.Event;
   import flash.events.MouseEvent;
   import flash.text.TextField;
   
   public class Main extends Sprite
   {
      
      public function Main():void {
         
         if (stage) _init();
         else addEventListener(Event.ADDED_TO_STAGE, _init);
      }
      
      
      private var txt:TextField = new TextField();
      private var btn:Sprite = new Sprite();
      
      private function _init(e:Event = null):void {
         /**
          * is called once the SWF movie is loaded and intialized on its own
          */
         removeEventListener(Event.ADDED_TO_STAGE, init);
         // entry point
         CSXSInterface.instance.addEventListener(StateChangeEvent.WINDOW_OPEN,_panelInitialized);
         
         //setup the textField
         addChild(txt);
         txt.border  = true;
         txt.height = 64 - 24-8;
         txt.text = "SWF panel loaded";
         txt.selectable = false;
         txt.y = 24;
         
         //create simple button
         addChild(btn);
         btn.graphics.beginFill(0xff0000);
         btn.graphics.drawRect(0, 0, 64, 16);
         btn.x = btn.y = 4;
         btn.mouseEnabled = true;
         btn.addEventListener(MouseEvent.ROLL_OVER, function rollOver(e:*):void { btn.alpha = 0.5 } );
         btn.addEventListener(MouseEvent.ROLL_OUT, function rollOver(e:*):void { btn.alpha = 1.0 } );
         btn.addEventListener(MouseEvent.CLICK, function btnClick(e:MouseEvent):void {
            trace("Button click");
            CSXSInterface.instance.evalScript("test", "Konnichiwa");
            txt.appendText("\nbtn click");
         } );
      }
      
      private function _panelInitialized():void {
         /**
          * is triggered once the SWF panel is initialized
          */
         txt.text = "PS panel initialized";
         CSXSInterface.instance.evalScript("test","Konnichiwa");//call for the JSX function called "test" with the parameter "Konnichiwa"
      }
      
   }
}
I hope that helps you further, button calls work the way you want it
izo

Getting started with PS CS4 Panels.. need some help

Post by izo »

thanks a lot for that !!!

that help,
on panel open is an example, in my case i wish on a click button.
but i don't know action script, there is a way to do that on mxml ?


this don't work for exemple, what modification i need to do for get it work ?
Thanks a lot for your, time. You really really help me
i'll become crazy, one days for write my jsx lib, and 1 week for try to get a flash interface. configurator is to cheap, and use flash in jsx directly, focus the windows and don't allow to use photohsop at the same time.

here my code - mxml :

Code: Select all

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="absolute" width="218" height="185">
            
   <mx:Script>
      <![CDATA[
         import com.adobe.csxs.core.CSXSInterface;    
         import com.adobe.csxs.types.*;
      
         [Embed(source="GrfsTools.jsx",mimeType="application/octet-stream")]
         private static var HolaWorldJS : Class;         
         
         public function executeJSX():void{
            CSXSInterface.instance.evalScript("test","Konnichiwa");
         }      
      
      ]]>
   </mx:Script>
      <mx:Label x="10" y="10" text="Hola World"/>
   <mx:Button x="10" y="39" label="Button" click="executeJSX()"/>
</mx:Application>


and my jsx

Code: Select all
function test(toto) {
alert(toto);
}
izo

Getting started with PS CS4 Panels.. need some help

Post by izo »

DAMN, my exemple works......


ok, now i can send one arguments, how i can send multiple arguments ?