Copy link to clipboard
Copied
Hey guys, I wanted to share a little JSX module I made to recursively get all the properties in an ActionDescriptor. It's always been a struggle to read the contents of an Action Descriptor, so I wanted something fast that could give me all this information without having to loop through every property manually.
I've seen many scripts out there trying to accomplish something similar, all of them with different and interesting approaches. I've definitely picked up a lot of ideas from these forums. I wasn't getting what I was looking for unfortunately, so I made my own module. This will mostly be used as a read-only JSON to look for the property that you need.
Here you will find the public repo for the project with all its information. Feel free to bring up ideas, bugs, compatibility issues, etc.
GitHub - JavierAroche/descriptor-info
Here's an example of how to use it.
descriptorInfo.getProperties( desc );
// Sample code for getting Descriptor properties with getProperties
// Include the descriptorInfo module
#include "~/Development/personal/descriptor-info/jsx/descriptor-info.jsx"
// ActionDescriptor example
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
// Retrieve its properties by running the getProperties function, passing the ActionDescriptor as a param
var descObject = descriptorInfo.getProperties( desc );
JSON object example: GitHub - JavierAroche/descriptor-info - JSON Example
REFERENCETYPE Descriptors will only return the Descriptor linked, but not it's actual properties. Adding this without properly testing can fall in an endless loop.
RAWTYPE Descriptors, usually labeled "legacyContentData", will return the value as unicode. You will have to parse it separately as the data varies too much.
Hope you guys find this useful and helps you better understand Action Descriptors. Feedback is always appreciated
PS. If you're using my Brackets-to-Photoshop extension, you can use the console.stringify function to print out the JSON descriptor to the console.
// Retrieve its properties by running the getProperties function, passing the ActionDescriptor as a param
var descObject = descriptorInfo.getProperties( desc );
console.stringify( descObject );
Copy link to clipboard
Copied
It does not work in CS6 Windows10.
console.log(descProperties.stringID + ' - ' + err) line console is not defined.
There is nowhere where you are printing the results or reference to Json.
Copy link to clipboard
Copied
Hey SuperMerlin​ thanks for trying it out!
Are you using my Brackets-to-Photoshop extension?
GitHub - JavierAroche/brackets-to-photoshop
The Brackets extension has its own internal console module to extend this functionality, as well as its own console in the UI. It uses Adobe's Brackets editor, so if you're using ExtendScript Toolkit then console.log won't work.
Copy link to clipboard
Copied
Thanks for the info. As an old age pensioner I am a bit slow on grasping new tech
I have tried but still failed, as can not find where to run the code from within Brackets, I noticed in your notes it said...
"* This extension uses Photoshop's AppleScript API, so it will only work for MacOS users at the moment."
As I am on Windows 10 does this mean I can't use it?
Thanks for your patience!
Copy link to clipboard
Copied
Ah you're on Windows! Yes, unfortunately I haven't implemented the Windows compatibility feature on my brackets extension. Hopefully I'll have some time to do it on January.
You can still use this descriptor-info module in ExtendScript Toolkit. The getProperties function will return an object, so you will need a JSON polyfill to stringify the object. I use this JSON polyifill all the time (Line 17).
https://github.com/JavierAroche/brackets-to-photoshop/blob/master/jsx/Helpers.jsx
Later today, maybe on Monday, I will add a little example to my repo with this polyfill included so you can just pick up the example and run it in ES Toolkit.
Copy link to clipboard
Copied
Thanks but I will stick with ESTK as I can get all the details I want.
But it might be useful for a lot of other people!
Keep up the good work Javier.
Copy link to clipboard
Copied
Good to see people like you on this forum. I think shortly I should start reading about json. Its style is quite readable, without many unimportant stuff for eyes you're enforced to see in ScriptListener / ActionManager code. Good job Javier!
Copy link to clipboard
Copied
Thx a lot. I will check it in January. Thanks also for MIT license.
"jam" framework does similar job, but it is under GPL license and GPL is connected with certain things, which I'm not sure.
JSON Action Manager | Tonton Pixel (website is sometimes offline)
Copy link to clipboard
Copied
Thanks but I will stick with ESTK as I can get all the details I want.
But it might be useful for a lot of other people!
Keep up the good work Javier.
Thanks SuperMerlin​! I stopped using ESTK because it was very buggy. Modern browsers offer a lot of great new features, most of them are open source, and Brackets in particular has a pretty good platform to create extensions using Node, which opens up to endless possibilities.
By the way, I added an example JSX to my repo (JSON polyfill included) so you can run it directly in ESTK. If you can/want, give it a try
descriptor-info/example at master · JavierAroche/descriptor-info · GitHub
Good to see people like you on this forum. I think shortly I should start reading about json. Its style is quite readable, without many unimportant stuff for eyes you're enforced to see in ScriptListener / ActionManager code. Good job Javier!
Hey Kukurykus​, thank you! Yes, JSON is definitely something you want to look into. It's unfortunate that functions like JSON.stringify or JSON.parse are not included in ExtendScript. That's why I added a polyfill in the example, so it's easier to preview the returned object.
Thx a lot. I will check it in January. Thanks also for MIT license.
"jam" framework does similar job, but it is under GPL license and GPL is connected with certain things, which I'm not sure.
JSON Action Manager | Tonton Pixel (website is sometimes offline)
Hey Jarda Bereza​, no problem! Yeah, I saw Tonton Pixel's code, and we actually have similar results. The returned object has a different structure though. Chose whichever one works best for you. The good thing is now we have 2 options!
Copy link to clipboard
Copied
It seems to be very usefull and more readable than Tonton Pixel's code. But you are not solving messed up Char/StringIDs
E.g. grain instead green
"color": {
"stringID": "color",
"charID": "Clr ",
"id": 1131180576,
"key": 3,
"type": "DescValueType.OBJECTTYPE",
"value": {
"count": 3,
"typename": "ActionDescriptor"
},
"object": {
"red": {
"stringID": "red",
"charID": "Rd ",
"id": 1382293536,
"key": 0,
"type": "DescValueType.DOUBLETYPE",
"value": 255
},
"grain": {
"stringID": "grain",
"charID": "Grn ",
"id": 1198681632,
"key": 1,
"type": "DescValueType.DOUBLETYPE",
"value": 255
},
"blue": {
"stringID": "blue",
"charID": "Bl ",
"id": 1114382368,
"key": 2,
"type": "DescValueType.DOUBLETYPE",
"value": 255
}
}
},
I did some measurements because only with only selected two groups the script was runing 10+ seconds. Which is too long.
Every lines in code has under 20ms except this:
case 'DescValueType.REFERENCETYPE': listArray.push( executeActionGet( listItemValue ) );
Time spend here was 10.3 seconds and this line was performed six times.
I suggest comment this line because it doesn't seems to have valuable info now and it will be lightning fast.
The only difference is, that I don't see "count"
Before/After
Copy link to clipboard
Copied
Hey Jarda Bereza​, thanks for taking the time to test this!
But you are not solving messed up Char/StringIDs
I'm only reading what's in the descriptor. I'm not changing any of the information, so it's accurate.
According to Tom Ruark's post here, stringIDToTypeID('grain') == stringIDToTypeID('green'). So it shouldn't be problem if you use the "grain" stringID.
Is there a reason you think I should modify messed up stringIDs? And do you know which other stringIDs are affected?
I suggest comment this line because it doesn't seems to have valuable info now and it will be lightning fast.
Yes, that's a good suggestion. I initially returned the descriptor so I could give the user the ability to use that referenced descriptor and analyze it. But, since this plugin is simply an info getter, it makes sense to not return a descriptor inside the object.
I'll include it in the v1.0.1 release. I'll post here when it's up.
Thanks!
Copy link to clipboard
Copied
v1.0.1 is up! If you're using this JSX, please pull the latest JSX / example
https://github.com/JavierAroche/descriptor-info
Copy link to clipboard
Copied
Here is mess table: Tonton-Pixel-Photoshop-Scripts/Decision table for conflicting StringIDs in Photoshop.pdf at master ·...
It is from: 2011 so maybe is not complete in 2017. I will check later if we need change it.
Anyway the power of your script is that i can read values and then use it on the next lines in code.
E.g.
var bgColor = descObject.artboard.object.color.object;
colorToHex(bgColor.red.value, bgColor.grain.value, bgColor.blue.value);
Which is awesome human friendly syntax if you compare this with script listener syntax.
But sometimes you will be forced to use unexpected names. This can cause a little confusion.
My next question is...
Is possible get value without writing ".value" ?
bgColor.red
//instead
bgColor.red.value
I can imagine that I will write .value everywhere because this is most important information and code will be a less readable. Maybe prototype._toString could handle this job? Everything else could be same. Also in ExtendScript Toolkit Data Browser would be more readable because you would see "left = 540" instead "left = [object Object] and you don't need go so deep in tree where is "value = 540" and then look above value of which.
Copy link to clipboard
Copied
But sometimes you will be forced to use unexpected names. This can cause a little confusion.
Is possible get value without writing ".value" ?
Jarda Bereza​, I see what you're saying on both points. I initially wrote this module to be a read only object. But it would be pretty cool to return a simplified object that you could use in your code.
I've thought about doing this before. Instead of having an object like the one in the repo README, you would get something simplified, like this:
{
"name": "Background",
"visible": true,
"mode": "
normal
","opacity": 255,
"layerID": 1,
"bounds": {
"top": 0,
"left": 0,
"bottom": 2500,
"right": 1594
},
"smartObject": {
"placed": "rasterizeContent",,
"documentID": "xmp.did:bfeed619-610f-4c23-9a5d-d03a5d55286e",
"compsList": { ...
},
"linked": false,
"fileReference": "imac_performance_and_design.psb"
},
"targetChannels": [
{
"typename": "ActionReference"
},
{
"typename": "ActionReference"
},
{
"typename": "ActionReference"
}
],
"channelRestrictions": [
"red",
"grain",
"blue"
],
...
}
I do want to keep the current main functionality though, which is to give you all the properties of the descriptor object: stringID, charID, id, key, type and value. I think that information is also very useful.
"name": {
"stringID": "name",
"charID": "Nm ",
"id": 1315774496,
"key": 0,
"type": "DescValueType.STRINGTYPE",
"value": "Background"
},
I think what I'll do is rework this module to return a simplified object, like the one I listed above, which would be the default returned object. And, I will add an "extended" flag to the descParams, which will retrieve the full object as it does right now (as listed in the README).
So it would look something like this in your JSX
var descFlags = {
reference : false,
extended : true
};
var descObject = descriptorInfo.getProperties( desc, descFlags );
What do you think?
Copy link to clipboard
Copied
Yes, this solution would be perfect! 🙂
And my code using your "framework" would be readable as never before 🙂
It also could a little bit improve performance if you read hunderds of layers and extended version will be disabled.
Copy link to clipboard
Copied
And my code using your "framework" would be readable as never before 🙂
Cool!
I will definitely work on that update and release a v1.0.2 as soon as I get some free time to work on this.
Thanks for trying it out and for the input!
For the messed up charIDs and stringIDs. I might have another flag to resolve those specific issues. I like the idea of delivering exactly what's in the descriptor, but I do want the module to have the flexibility to pass a specific parameter so you can return what you need.
It would look something like this:
var descFlags = {
reference : false,
extended : true,
fixIDs : true
};
var descObject = descriptorInfo.getProperties( desc, descFlags );
Copy link to clipboard
Copied
It think fixIDs option would be ok.
I wonder if there is any possibility to get list of all descriptors that can be disassembled.
You can read app preferences, but not all preferences as I know, history states, paths panel, channels pannel, documents... what else?
I am thinking about possibility to more easy way how to get properties.
Something like:
descObject = descriptorInfo.getSelectedLayersProperties( descFlags );
or
decsObject = descriptorInfo.getLayersPropertiesByIndex( [45,20,123], descFlags );
or
decsObject = descriptorInfo.getLayersPropertiesById( [45,20,123], descFlags );
similar for app settings and next frequently used things.
Copy link to clipboard
Copied
Hey Jarda Bereza​, I feel like that would deviate a little bit from the module's core functionality.
I do agree that we need an extended Photoshop API. We've actually built our own internal Photoshop API / NPM module at work (with over 100 setter / getter functions), combining Photoshop's JavaScript API and ActionManager code. We made it so it can be used inside Generator, in a CEP Panel, or in a standalone node module that connects to Photoshop. But unfortunately it's internal only
We have function such as:
Which makes it super useful to not have to repeat code and maintain.
Copy link to clipboard
Copied
Hey guys,
I just realized v1.0.2 of my descriptor-info JSX module. I've simplified the object returned to make it more useable. I've updated the object examples in the README to show the new changes.
Please check it out, if you have some time.
https://github.com/JavierAroche/descriptor-info
v1.0.2 (Jan 13 2017)
Jarda Bereza​, let me know what you think!
Copy link to clipboard
Copied
This is pretty good 🙂
I will rewrite my old code.
"desc.bounds.top" will be better than
"desc['bounds'][1][1]['top'][1][1]"
and still faster than classic DOM.
Maybe JAM framework can also do that but I am not able figure it. If I turn off "parse friednly" i see
desc.boundsNoMask.<object>.rectangle.top But I am not able get inside <object>
I think reference flag is not self-explaning. I am not sure if true means off or on.
May next Idea is create some dictionary which will show you tree differences between Photoshop version. It could be somehow automated and it would compare JSON trees. It would open one PSD in different PS version and test same layer JSON trees. If you have Cloud subscription you have access to all version from CS6 to CC2017.
E.g. CS6 doesn't have "width" and "height" in "bounds" But I am not sure how output should look like. I really like this webpage: http://caniuse.com/#search=json 😄
Copy link to clipboard
Copied
Thanks Jarda Bereza​!
Maybe JAM framework can also do that but I am not able figure it. If I turn off "parse friednly" i see
desc.boundsNoMask.<object>.rectangle.top But I am not able get inside <object>
I've only used the JAM framework to read the object, not use its properties. So I've never dealt with the structure of the object.
I think reference flag is not self-explaning. I am not sure if true means off or on.
This is my current description for the reference flag
Any suggestions as to what would make it a little more clear?
May next Idea is create some dictionary which will show you tree differences between Photoshop version. It could be somehow automated and it would compare JSON trees. It would open one PSD in different PS version and test same layer JSON trees. If you have Cloud subscription you have access to all version from CS6 to CC2017.
That would be interesting. Adobe has changed their descriptors. We don't have a cloud subscription at work, so I can't test all of them But it would be interesting to see.
E.g. CS6 doesn't have "width" and "height" in "bounds" But I am not sure how output should look like. I really like this webpage: http://caniuse.com/#search=json 😄
This module should just read whatever is in the descriptor, so if width and height in bounds are not there, it just won't show them.
I don't think JSON compatibility is an issue here. Using the JSON polyfill I included in the example you should be ok, it's plain JavaScript.
Copy link to clipboard
Copied
Any suggestions as to what would make it a little more clear?
Maybe I will try to compare property trees between PS versions in future. But I am not sure what is best a most usefull way, to show results. Can-I-use link was one way how to interpret these results. It wasn't about polyfill.
Copy link to clipboard
Copied
- Optional @flag {Boolean} reference - if value is false then return reference descriptors. Could slightly affect speed. In some cases 10 seconds per descriptor.
If the reference flag is true, it will return de descriptor inside the reference object. So it will do a "executeActionGet( ref )", which is why it returns a descriptor, and could take a little longer.
If the reference flag is false, it will only return the reference object, which means if you want to use that reference later in your code, you'll have to do the "executeActionGet( ref )" by yourself. That's why it might be a little faster.
Maybe I will try to compare property trees between PS versions in future. But I am not sure what is best a most usefull way, to show results. Can-I-use link was one way how to interpret these results. It wasn't about polyfill.
Ah got it. I use this little github project to easily read my JSON objects. I find it super useful.
Copy link to clipboard
Copied
Hi JavierAroche​
Thank for your work. I can't get value of property of descObject by access descObject[property]
var descObject = descriptorInfo.getProperties( desc, descFlags );
JSON.stringify(descObject) ===> Failed here
==> so I switch to:
for (var property in descObject) {
if (descObject.hasOwnProperty(property)) {
// do stuff
i++;
try {
arr.push(i+': '+(property)); // this is OK, I can get all property of descObject
//descObject[property] //this not OK, I can't get the value of property
}catch(e){
continue;
}
}
}
Do you have any advise?
Thanks,
Copy link to clipboard
Copied
Hi JavierAroche​
Sorry, look like issue came from psd file not from the code. If I use the code with simple and clean PSD, it is OK but for complex (that I'm not sure if layer name contain unicode character or any else...) code will not working normally. It's still show information to console but not write to text file as I expect.
Continue debugging.
Thanks,