Skip to main content
Participant
April 28, 2015
Answered

What? ActionReference, charIDToTypeID, stringIDToTypeID

  • April 28, 2015
  • 2 replies
  • 17209 views

Hi,

I am newbie to photoshop scripting but I do have few years experience with Javascript. Looking for clarification as I can't figure out what is  going on here.

I was looking for solution how to get array of selected artLayers and layersSets. I found couple solutions on blogs and forums which works, but I can't figure out what that code actually does so may someone could explain it line by line or point me to normal documentation as I found http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/photoshop/pdfs/photoshop_scriptref_ js.pdf doesn't explain anything just gives list of available functions.

How ActionDescriptor, ActionReference works, how returned object by executeActionGet(ref) is structured and how Photoshop stores actions in memory.

var ref = new ActionReference();

var selectedLayers = [];

ref.putEnumerated( // Puts an enumeration type and ID into a reference along with the desired class for the reference.

     //why I do need use putEnumerated? what it gives?

     charIDToTypeID("Dcmn"), // document

     charIDToTypeID("Ordn"), // typeOrdinal - what is ordinal?

     charIDToTypeID("Trgt") //enumTarget - what?why?

)

var desc = executeActionGet(ref); // returns ActionDescriptor, how this object structure looks? how it was created?

desc = desc.getList( stringIDToTypeID( 'targetLayers' )); //returns ActionList, but what is targetLayers,who specified targetLayers? or it means it targets all layers?

for(var i=0;i<c;i++){

            try{              

               selectedLayers.push(  desc.getReference( i ).getIndex() );//gets action reference index in the ActionList

            }catch(e){

              // selectedLayers.push(  desc.getReference( i ).getIndex()+1 ); //I commented this out as I can't understand why it is used, if we failed for i, how I can be sure that we will not fail for i+1??

            }

}

If I understand correctly it gives me indexes of actions but not layers. Is that right? After this code I should somehow get artLayer+layersSets by using action indexes?

--------------------------

--------------------------My structure of layers and groups is

   Layer 4

Group4(1)

      Layer 3

   Group 3(1)

Group 2(1)

   Layer 2

Group 1(1)

Layer 5

Layer 1

and when I select all groups ant layers script above which should return array of selected layers/groups indexes returns me this - 1,2,4,5,8,9,10,12,13. As you can see it is missing some numbers so I assume this is not array of layers indexes.

Thank you!

Tomas

Correct answer DBarranca

Hi Tomas,

welcome to this land of sorrows ;-)

Shortly put, Photoshop DOM coverage isn't full. Where the DOM is missing, ActionManager (AM) code fills the gaps.

For instance you can

app.activeDocument.activeLayer.applyGaussianBlur(20);

but when it comes to applying a Curve you just have to:

var idCrvs = charIDToTypeID( "Crvs" );

    var desc8 = new ActionDescriptor();

    var idpresetKind = stringIDToTypeID( "presetKind" );

    var idpresetKindType = stringIDToTypeID( "presetKindType" );

    var idpresetKindCustom = stringIDToTypeID( "presetKindCustom" );

    desc8.putEnumerated( idpresetKind, idpresetKindType, idpresetKindCustom );

    var idAdjs = charIDToTypeID( "Adjs" );

        var list1 = new ActionList();

            var desc9 = new ActionDescriptor();

            var idChnl = charIDToTypeID( "Chnl" );

                var ref3 = new ActionReference();

                var idChnl = charIDToTypeID( "Chnl" );

                var idChnl = charIDToTypeID( "Chnl" );

                var idCmps = charIDToTypeID( "Cmps" );

                ref3.putEnumerated( idChnl, idChnl, idCmps );

            desc9.putReference( idChnl, ref3 );

            var idCrv = charIDToTypeID( "Crv " );

                var list2 = new ActionList();

                    var desc10 = new ActionDescriptor();

                    var idHrzn = charIDToTypeID( "Hrzn" );

                    desc10.putDouble( idHrzn, 0.000000 );

                    var idVrtc = charIDToTypeID( "Vrtc" );

                    desc10.putDouble( idVrtc, 0.000000 );

                var idPnt = charIDToTypeID( "Pnt " );

                list2.putObject( idPnt, desc10 );

                    var desc11 = new ActionDescriptor();

                    var idHrzn = charIDToTypeID( "Hrzn" );

                    desc11.putDouble( idHrzn, 70.000000 );

                    var idVrtc = charIDToTypeID( "Vrtc" );

                    desc11.putDouble( idVrtc, 75.000000 );

                var idPnt = charIDToTypeID( "Pnt " );

                list2.putObject( idPnt, desc11 );

                    var desc12 = new ActionDescriptor();

                    var idHrzn = charIDToTypeID( "Hrzn" );

                    desc12.putDouble( idHrzn, 179.000000 );

                    var idVrtc = charIDToTypeID( "Vrtc" );

                    desc12.putDouble( idVrtc, 212.000000 );

                var idPnt = charIDToTypeID( "Pnt " );

                list2.putObject( idPnt, desc12 );

                    var desc13 = new ActionDescriptor();

                    var idHrzn = charIDToTypeID( "Hrzn" );

                    desc13.putDouble( idHrzn, 255.000000 );

                    var idVrtc = charIDToTypeID( "Vrtc" );

                    desc13.putDouble( idVrtc, 255.000000 );

                var idPnt = charIDToTypeID( "Pnt " );

                list2.putObject( idPnt, desc13 );

            desc9.putList( idCrv, list2 );

        var idCrvA = charIDToTypeID( "CrvA" );

        list1.putObject( idCrvA, desc9 );

    desc8.putList( idAdjs, list1 );

executeAction( idCrvs, desc8, DialogModes.NO );

The above code is the output of the ScriptingListener plugin made by Adobe's Tom Ruark (available in the devnet section of the PS site) and it's the base of our AM understanding, since the only and closest thing to an official documentation is a 1999 pdf about building automation plugins in C/C++ for Photoshop 5.5.

There are tutorials in the ps-scripts.com website about ActionManager mainly by Mike Hale (who BTW seems to have stopped posting, lately - I hope he's well!) and xBytor.

A couple of threads are http://www.ps-scripts.com/bb/viewtopic.php?f=16&t=5210&sid=8c4436e880b87815b9492377175cac2b and http://ps-scripts.com/bb/viewtopic.php?f=15&t=340&sid=425050a8d59fcc724e5c325f51520b5c

Think about ActionDescriptors more or less like russian dolls that you use to get and/or set properties, or executing actions.

In the snippet you posted, you have built an ActionReference specifying that you're interested in the current Document (the Dcmn, Ordn, Trgt thing - I'm afraid that's the way it is: if you want to use, as I prefer, the more understandable stringIDs, it becomes stringIDToTypeID ("document"), stringIDToTypeID ("ordinal"), stringIDToTypeID ("targetEnum")).

Then you actually retrieve the Document's Descriptor via executeActionGet, feeding the function with the ActionReference you've built.

Now you have this big fat Descriptor, which contains all sort of stuff (see ps-scripts.com for descriptor inspectors code, which helps you identifying what's in there).

Then you've extracted an ActionList via getList(), specifying that you're interested in the very one which key is stringIDToTypeID( 'targetLayers' ). Etc, etc.


Mind you, when it comes to AM code and layers / layerSets, you can use indexes and IDs - I can be wrong because I don't use layerSets too much myself, but I remember they have a trailing index (that is, a layerSet has a starting index, and a hidden, closing index, which **might** be the reason for the +1 in the catch - others can help you with more accurate information).


Hope this helps!

Kind regards,


Davide Barranca

---

www.davidebarranca.com

www.cs-extensions.com

2 replies

Participant
April 29, 2015

Just want to add some notes for others if they will look for clarification.

For me really helped this .jsx scrip( http://ps-scripts.cvs.sourceforge.net/viewvc/ps-scripts/xtools/apps/GetterDemo.jsx ) as it gives you  Action Descriptor containing data, by digging in to this data and comparing how developers access it clarified a lot!

At start it is really overwhelming and painful but you need to learn to live with it.

Now let's create some extensions!

Participant
April 29, 2015

Just some quick notes:

1)  GetterDemo is based on a demo program in the PS SDK. I haven't updated it to reflect any changes for several years. There may be more interesting tidbits that can be pulled from newer revs that I am not aware of. I'll take a look when the next major PS rev is dropped.

2) Starting with CC or CC2014, a lot more information was getting dumped by GetterDemo, probably from the Application Descriptor tree. I had to modify GetterDemo to save the data to an XML file because otherwise it would blowup when I tried to stuff it into a static or edit text widget. There is apparently an undocumented limit in there that I was breaking. I'm not sure if the current xtools.zip file has the most recent rev, but the link that kugelis provided should be the most recent version.

3) http://ps-scripts.cvs.sourceforge.net/viewvc/ps-scripts/xtools/xlib/PSConstants.js may help getting your head around some of the terminology.

4) I've been doing this since PS7 and know this stuff about as well as anybody outside of Adobe. They actually made some minor changes to the AM docs based on my input but it is still far from complete. Random people still drop out pieces AM code with magic numbers in it that I have no clue where they found them, probably something from the SDK code. In other words, the is no canonical source for info on AM programming.

5) My best advice is to study ScriptingListener output and to search for pre-existing posts or code examples. There is a lot of stuff in xtools as well as posts here and at ps-scripts.com to look at. But, honestly, it will not be an easy road.

6) Realize that there are some things that cannot be done either through the DOM or AM code. Unfortunately not everything is plugged into the automation framework so there are limitations as to what can be done via JavaScript.

Participant
April 29, 2015

Thank you for your input, appreciate it.

DBarranca
DBarrancaCorrect answer
Legend
April 28, 2015

Hi Tomas,

welcome to this land of sorrows ;-)

Shortly put, Photoshop DOM coverage isn't full. Where the DOM is missing, ActionManager (AM) code fills the gaps.

For instance you can

app.activeDocument.activeLayer.applyGaussianBlur(20);

but when it comes to applying a Curve you just have to:

var idCrvs = charIDToTypeID( "Crvs" );

    var desc8 = new ActionDescriptor();

    var idpresetKind = stringIDToTypeID( "presetKind" );

    var idpresetKindType = stringIDToTypeID( "presetKindType" );

    var idpresetKindCustom = stringIDToTypeID( "presetKindCustom" );

    desc8.putEnumerated( idpresetKind, idpresetKindType, idpresetKindCustom );

    var idAdjs = charIDToTypeID( "Adjs" );

        var list1 = new ActionList();

            var desc9 = new ActionDescriptor();

            var idChnl = charIDToTypeID( "Chnl" );

                var ref3 = new ActionReference();

                var idChnl = charIDToTypeID( "Chnl" );

                var idChnl = charIDToTypeID( "Chnl" );

                var idCmps = charIDToTypeID( "Cmps" );

                ref3.putEnumerated( idChnl, idChnl, idCmps );

            desc9.putReference( idChnl, ref3 );

            var idCrv = charIDToTypeID( "Crv " );

                var list2 = new ActionList();

                    var desc10 = new ActionDescriptor();

                    var idHrzn = charIDToTypeID( "Hrzn" );

                    desc10.putDouble( idHrzn, 0.000000 );

                    var idVrtc = charIDToTypeID( "Vrtc" );

                    desc10.putDouble( idVrtc, 0.000000 );

                var idPnt = charIDToTypeID( "Pnt " );

                list2.putObject( idPnt, desc10 );

                    var desc11 = new ActionDescriptor();

                    var idHrzn = charIDToTypeID( "Hrzn" );

                    desc11.putDouble( idHrzn, 70.000000 );

                    var idVrtc = charIDToTypeID( "Vrtc" );

                    desc11.putDouble( idVrtc, 75.000000 );

                var idPnt = charIDToTypeID( "Pnt " );

                list2.putObject( idPnt, desc11 );

                    var desc12 = new ActionDescriptor();

                    var idHrzn = charIDToTypeID( "Hrzn" );

                    desc12.putDouble( idHrzn, 179.000000 );

                    var idVrtc = charIDToTypeID( "Vrtc" );

                    desc12.putDouble( idVrtc, 212.000000 );

                var idPnt = charIDToTypeID( "Pnt " );

                list2.putObject( idPnt, desc12 );

                    var desc13 = new ActionDescriptor();

                    var idHrzn = charIDToTypeID( "Hrzn" );

                    desc13.putDouble( idHrzn, 255.000000 );

                    var idVrtc = charIDToTypeID( "Vrtc" );

                    desc13.putDouble( idVrtc, 255.000000 );

                var idPnt = charIDToTypeID( "Pnt " );

                list2.putObject( idPnt, desc13 );

            desc9.putList( idCrv, list2 );

        var idCrvA = charIDToTypeID( "CrvA" );

        list1.putObject( idCrvA, desc9 );

    desc8.putList( idAdjs, list1 );

executeAction( idCrvs, desc8, DialogModes.NO );

The above code is the output of the ScriptingListener plugin made by Adobe's Tom Ruark (available in the devnet section of the PS site) and it's the base of our AM understanding, since the only and closest thing to an official documentation is a 1999 pdf about building automation plugins in C/C++ for Photoshop 5.5.

There are tutorials in the ps-scripts.com website about ActionManager mainly by Mike Hale (who BTW seems to have stopped posting, lately - I hope he's well!) and xBytor.

A couple of threads are http://www.ps-scripts.com/bb/viewtopic.php?f=16&t=5210&sid=8c4436e880b87815b9492377175cac2b and http://ps-scripts.com/bb/viewtopic.php?f=15&t=340&sid=425050a8d59fcc724e5c325f51520b5c

Think about ActionDescriptors more or less like russian dolls that you use to get and/or set properties, or executing actions.

In the snippet you posted, you have built an ActionReference specifying that you're interested in the current Document (the Dcmn, Ordn, Trgt thing - I'm afraid that's the way it is: if you want to use, as I prefer, the more understandable stringIDs, it becomes stringIDToTypeID ("document"), stringIDToTypeID ("ordinal"), stringIDToTypeID ("targetEnum")).

Then you actually retrieve the Document's Descriptor via executeActionGet, feeding the function with the ActionReference you've built.

Now you have this big fat Descriptor, which contains all sort of stuff (see ps-scripts.com for descriptor inspectors code, which helps you identifying what's in there).

Then you've extracted an ActionList via getList(), specifying that you're interested in the very one which key is stringIDToTypeID( 'targetLayers' ). Etc, etc.


Mind you, when it comes to AM code and layers / layerSets, you can use indexes and IDs - I can be wrong because I don't use layerSets too much myself, but I remember they have a trailing index (that is, a layerSet has a starting index, and a hidden, closing index, which **might** be the reason for the +1 in the catch - others can help you with more accurate information).


Hope this helps!

Kind regards,


Davide Barranca

---

www.davidebarranca.com

www.cs-extensions.com

Participant
April 28, 2015

Thank you for all the details, I will definitely check articles that you recommend, I hope it will clarify a lot.

1999 pdf?? Wow, Adobe...Never thought is THAT bad. Well I need to join Adobe team and fix this mess.

Mine customer experience  is very bad, as it is so painful to start improving Adobe products eco-system. Even all these reference .pdf documents, try read them on 5" mobile screen...It seems that Adobe still lives in 2004.