Copy link to clipboard
Copied
Hello,
Yeah, it's me again... so in the recent weeks, I've been able to understand a bit better how Action Manager code works, and I started writing my own functions to get to some specific things...
But that being said, I'm still having trouble with some stuff.
At the moment, I'm trying to determine if any blending options are applied to a layer. My search so far got me to these "properties" : "channelRestrictions" (which is a list of 3 channels, red blue and grain (can't believe this one...)), "blendRange" which is related to the "blend if's" settings, and "knockout" which is related to ..well... Knockout's settings.
But I'm stuck there... can't get to the right way of using those... Somehow, I just want to know if any of those isn't in its default mode... So I'd know there is some kind of "blending options" going on ...
Any thoughts ?
Thanks !
Try
var r = new ActionReference();
var d = new ActionDescriptor();
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("json"));
r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
d.putReference(stringIDToTypeID("null"), r);
eval("var json="+executeAction(stringIDToTypeID("get"), d, DialogModes.NO).getString(stringIDToTypeID("json")));
if (json.layers[0].blendOptions) alert(json.layers[0].blendOptions.toSource());
else alert ("sta
...
Copy link to clipboard
Copied
activeDocument.activeLayer.blendMode == BlendMode.NORMAL
Copy link to clipboard
Copied
Nah. I'm not talking about the layer's "blending mode", I'm talking about "blending options".
Copy link to clipboard
Copied
Ah right, if I had time I could help, but probably someone else will do it soon 😉
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Thanks for the idea, but that doesn't work either. If a layer has a simple "blending mode" applied, and no "blending options", the "Copy layer Style" command is actually available.
Copy link to clipboard
Copied
ScriptListener returns these when I mess around with the blending options :
// =======================================================
var idset = stringIDToTypeID( "set" );
var desc1325 = new ActionDescriptor();
var idnull = stringIDToTypeID( "null" );
var ref815 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idtargetEnum = stringIDToTypeID( "targetEnum" );
ref815.putEnumerated( idlayer, idordinal, idtargetEnum );
desc1325.putReference( idnull, ref815 );
var idto = stringIDToTypeID( "to" );
var desc1326 = new ActionDescriptor();
var idchannelRestrictions = stringIDToTypeID( "channelRestrictions" );
var list72 = new ActionList();
var idchannel = stringIDToTypeID( "channel" );
var idred = stringIDToTypeID( "red" );
list72.putEnumerated( idchannel, idred );
var idchannel = stringIDToTypeID( "channel" );
var idblue = stringIDToTypeID( "blue" );
list72.putEnumerated( idchannel, idblue );
desc1326.putList( idchannelRestrictions, list72 );
var idlayer = stringIDToTypeID( "layer" );
desc1325.putObject( idto, idlayer, desc1326 );
executeAction( idset, desc1325, DialogModes.NO );
This one has to do with the 3 channels checkboxes. "channelRestrictions" is a "DescValueType.LISTTYPE" of the layer object in AM, so I can get to it, see if all channels are in the list. If not, blending options have been messed with. So this part is cool.
var idset = stringIDToTypeID( "set" );
var desc1321 = new ActionDescriptor();
var idnull = stringIDToTypeID( "null" );
var ref813 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idtargetEnum = stringIDToTypeID( "targetEnum" );
ref813.putEnumerated( idlayer, idordinal, idtargetEnum );
desc1321.putReference( idnull, ref813 );
var idto = stringIDToTypeID( "to" );
var desc1322 = new ActionDescriptor();
var idblendRange = stringIDToTypeID( "blendRange" );
var list71 = new ActionList();
var desc1323 = new ActionDescriptor();
var idchannel = stringIDToTypeID( "channel" );
var ref814 = new ActionReference();
var idchannel = stringIDToTypeID( "channel" );
var idchannel = stringIDToTypeID( "channel" );
var idgray = stringIDToTypeID( "gray" );
ref814.putEnumerated( idchannel, idchannel, idgray );
desc1323.putReference( idchannel, ref814 );
var idsrcBlackMin = stringIDToTypeID( "srcBlackMin" );
desc1323.putInteger( idsrcBlackMin, 127 );
var idsrcBlackMax = stringIDToTypeID( "srcBlackMax" );
desc1323.putInteger( idsrcBlackMax, 127 );
var idsrcWhiteMin = stringIDToTypeID( "srcWhiteMin" );
desc1323.putInteger( idsrcWhiteMin, 255 );
var idsrcWhiteMax = stringIDToTypeID( "srcWhiteMax" );
desc1323.putInteger( idsrcWhiteMax, 255 );
var iddestBlackMin = stringIDToTypeID( "destBlackMin" );
desc1323.putInteger( iddestBlackMin, 0 );
var iddestBlackMax = stringIDToTypeID( "destBlackMax" );
desc1323.putInteger( iddestBlackMax, 0 );
var iddestWhiteMin = stringIDToTypeID( "destWhiteMin" );
desc1323.putInteger( iddestWhiteMin, 255 );
var iddesaturate = stringIDToTypeID( "desaturate" );
desc1323.putInteger( iddesaturate, 255 );
var idblendRange = stringIDToTypeID( "blendRange" );
list71.putObject( idblendRange, desc1323 );
desc1322.putList( idblendRange, list71 );
var idlayer = stringIDToTypeID( "layer" );
desc1321.putObject( idto, idlayer, desc1322 );
executeAction( idset, desc1321, DialogModes.NO );
This has to do with the blend ifs. I'm guessing that if I could get to the individual values in there (the "srcBlackMin", "srcBlackMax", etc., I could probably detect if those are on their default value or not... I just can't see how to get to those values.
// =======================================================
var idset = stringIDToTypeID( "set" );
var desc1329 = new ActionDescriptor();
var idnull = stringIDToTypeID( "null" );
var ref817 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idtargetEnum = stringIDToTypeID( "targetEnum" );
ref817.putEnumerated( idlayer, idordinal, idtargetEnum );
desc1329.putReference( idnull, ref817 );
var idto = stringIDToTypeID( "to" );
var desc1330 = new ActionDescriptor();
var idknockout = stringIDToTypeID( "knockout" );
var idknockout = stringIDToTypeID( "knockout" );
var idshallow = stringIDToTypeID( "shallow" );
desc1330.putEnumerated( idknockout, idknockout, idshallow );
var idlayer = stringIDToTypeID( "layer" );
desc1329.putObject( idto, idlayer, desc1330 );
executeAction( idset, desc1329, DialogModes.NO );
Same goes for this one... it has to do with the knockout property of the layer... "Shallow" being one of the options available in the dropdown, I'm guessing that again, if I could get to that property, I could detect it's not set to "None" (the default value).
But when I dump all of a layers AM properties, I don't see any "blendMode" nor any "knockout".
How do you actually get to those ?
Many, many thanks.
J.
Copy link to clipboard
Copied
Try
var r = new ActionReference();
var d = new ActionDescriptor();
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("json"));
r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
d.putReference(stringIDToTypeID("null"), r);
eval("var json="+executeAction(stringIDToTypeID("get"), d, DialogModes.NO).getString(stringIDToTypeID("json")));
if (json.layers[0].blendOptions) alert(json.layers[0].blendOptions.toSource());
else alert ("standard");
Copy link to clipboard
Copied
Hey there. Not a big fan of using the eval() function, but I'm just amazed we can actually get a json string with most layers properties like this. I've been dreaming of such a thing in the last few weeks. Really really helps in understanding how layers are built.
Thanks a million ! I'll get it to work from there.
J.
Copy link to clipboard
Copied
Так понимаю, что вместо:
r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
фактически используется:
r.putEnumerated(stringIDToTypeID("document"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
(оба варианта дают одинаковый результат, но по структуре это именно json документа)
Вообще неожиданно - думал, что все свойства слоя можно получить из его дескриптора обычным способом.
Copy link to clipboard
Copied
Оно отличается как минимум количеством слоёв в объекте.
Там полно глюков с этим json, разные в разных версиях. Есть проблемы с "Enumerated".
Можно тут почитать кое-что полезное
Photoshop Kevlar API Additions for Generator
Можно задавать доп.фильтры или параметры, чтобы получить только нужные или недоступные по умолчанию параметры (типа как "get", но без "property").
Copy link to clipboard
Copied
The core of code you may make simpler up to 15-20 times faster,
so without: ActionDescriptor, Enumeration, null, get and variable:
sTT = stringIDToTypeID; (ref = new ActionReference()).putProperty
(sTT('property'), jsn = sTT('json')), ref.putClass(sTT('layer'))
eval('(' + executeActionGet(ref).getString(jsn) + ')')
Copy link to clipboard
Copied
Guys, it's hard to follow you when you start exchanging in anything but english...
I've been fiddling with the JSON object retuned by PS, and I am stumped to discover that it returns all layerSets in the document, even the ones that aren't parent to the specified layer. While I can imagine this could serve some kind of purpose sometime... it really does feel weird to me. I would have imagined that it would return only the selected layer, and it's parent layerSets...
For a PS document that looks like this :
I get a JSON like this :
(notice how the first "layers" branch returned (the one with Group 1, Group 2 and Group 3 in it)) has nothing to do with my selected layer.)
{
"version": "1.6.1",
"timeStamp": 1592246312.421,
"count": 20,
"id": 880,
"file": "/Volumes/JK_RAID_01/projets/20-007_Poussieres_de_Daesh/00_work/10_design/logo/on_Stills/Screen Shot 2020-06-08 at 10.49.54 PM-Recovered.psd",
"bounds": {
"top": 0,
"left": 0,
"bottom": 325,
"right": 532
},
"selection": [
10
],
"resolution": 72,
"globalLight": {
"angle": 30,
"altitude": 30
},
"generatorSettings": false,
"profile": "PA272W 62115745TW 2020-01-23 11-46 D65 2.20",
"mode": "RGBColor",
"depth": 8,
"layers": [
{
"id": 13,
"index": 22,
"type": "layerSection",
"name": "Group 1",
"bounds": {
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"visible": true,
"clipped": false,
"blendOptions": {
"mode": "passThrough"
},
"generatorSettings": false,
"layers": [
{
"id": 15,
"index": 21,
"type": "layerSection",
"name": "Group 2",
"bounds": {
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"visible": true,
"clipped": false,
"blendOptions": {
"mode": "passThrough"
},
"generatorSettings": false,
"layers": [
{
"id": 17,
"index": 20,
"type": "layerSection",
"name": "Group 3",
"bounds": {
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"visible": true,
"clipped": false,
"blendOptions": {
"mode": "passThrough"
},
"generatorSettings": false
}
]
}
]
},
{
"id": 29,
"index": 13,
"type": "layerSection",
"name": "Group 9",
"bounds": {
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"visible": true,
"clipped": false,
"blendOptions": {
"mode": "passThrough"
},
"generatorSettings": false,
"layers": [
{
"id": 27,
"index": 12,
"type": "layerSection",
"name": "Group 8",
"bounds": {
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"visible": true,
"clipped": false,
"blendOptions": {
"mode": "passThrough"
},
"generatorSettings": false,
"layers": [
{
"id": 25,
"index": 11,
"type": "layerSection",
"name": "Group 7",
"bounds": {
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"visible": true,
"clipped": false,
"blendOptions": {
"mode": "passThrough"
},
"generatorSettings": false,
"layers": [
{
"id": 23,
"index": 10,
"type": "layerSection",
"name": "Group 6",
"bounds": {
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"visible": true,
"clipped": false,
"blendOptions": {
"mode": "passThrough"
},
"generatorSettings": false,
"layers": [
{
"id": 21,
"index": 9,
"type": "layerSection",
"name": "Group 5",
"bounds": {
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"visible": true,
"clipped": false,
"blendOptions": {
"mode": "passThrough"
},
"generatorSettings": false,
"layers": [
{
"id": 19,
"index": 8,
"type": "layerSection",
"name": "Group 4",
"bounds": {
"top": 0,
"left": 0,
"bottom": 0,
"right": 0
},
"visible": true,
"clipped": false,
"blendOptions": {
"mode": "passThrough"
},
"generatorSettings": false
}
]
}
]
}
]
}
]
}
]
}
]
}
Is this the normal behaviour ?
I am getting the json this way :
function getLayerJson(theIndex) {
var r = new ActionReference();
var d = new ActionDescriptor();
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("json"));
r.putIndex(charIDToTypeID('Lyr '), theIndex);
d = executeActionGet (r);
return d.getString(stringIDToTypeID("json"));
}
Copy link to clipboard
Copied
You can try it like that
var r = new ActionReference();
var d = new ActionDescriptor();
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("json"));
r.putEnumerated(stringIDToTypeID("document"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
d.putReference(stringIDToTypeID("null"), r);
d.putBoolean(stringIDToTypeID("imageInfo"), false);
d.putBoolean(stringIDToTypeID( "includeAncestors" ), false);
//d.putBoolean( stringIDToTypeID( "selectedLayers" ), true); // for selected
//d.putInteger(stringIDToTypeID("layerID"), 4); // for id
d.putInteger(stringIDToTypeID("firstLayer"), 12); // for index
d.putInteger(stringIDToTypeID("lastLayer"), 12);
eval("var json="+executeAction(stringIDToTypeID("get"), d, DialogModes.NO).getString(stringIDToTypeID("json")));
alert(json.toSource())
Copy link to clipboard
Copied
This is quite interesting too.
Mostly works, but would there be a way to keep the whole "layerSection" hierarchy, but only for the layer I'm currently checking. I obviously tried to change the "includeAncestors" to true, but that brings it back to the original behaviour, which doesn't work for me...
Again... thanks for the help 😄
Copy link to clipboard
Copied
Bu sorunun cevabını bende arıyorum. evet sen biraz geliştirmişsin teşekkürler
Copy link to clipboard
Copied
Hello, seems like json code dont get channel value, it alerts empty value. So how to get the channel of blendif ?
Copy link to clipboard
Copied
addon: json string returns values splitted into a single character instead array values, how to get normal array values like "channel" instead of "c, h, a, n, n, e, l"?
Copy link to clipboard
Copied
Copy link to clipboard
Copied
1. Empty channel's name problem, how to get values of channel if I cant get the name? :
2. Layer's properties are separated characters instead of string. To get blendif values I'll have to use match or split commands.
var r = new ActionReference();
var d = new ActionDescriptor();
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("json"));
r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
d.putReference(stringIDToTypeID("null"), r);
eval("var json="+executeAction(stringIDToTypeID("get"), d, DialogModes.NO).getString(stringIDToTypeID("json")));
if (json.layers[0].blendOptions)
{
var xx = json.layers[0].blendOptions.toSource();
alert (xx.length); // counts xx as hundreds of characters
}
Copy link to clipboard
Copied
Copy link to clipboard
Copied
I don't see your question about "values like 'channel' instead of' c, h, a, n, n, e, l '? "
As for channel: "", this is most likely a script engine glitch.
There should be numbered channel values of type "red" or "gray", etc.
The json functionality changes from the version of photoshop.
At least in Photoshop 21.2.2 (like mine) this glitch is present.
It is necessary to write about an error on the feedback site.
You can try the following. Save the current file to a temporary one, parse it, find the required layer and take its parameters. But it takes a long time if the file is large, plus, it is necessary to have a function for parisign of PSD (PSB) files.
P.S. Perhaps in Photoshop 2021 it became possible to get blendOptions without using json, but for example through the properties of the layer itself. But I cannot check, because it is not possible to install it.
Copy link to clipboard
Copied
Thanks for reply r-bin. Too bad to hear about another one glitch. Anyway I made up a way to get those empry layer's names with simple script steps. I think I will post it here in a few days when ill finish it.
Copy link to clipboard
Copied
app.displayDialogs = DialogModes.NO;
var tmp_file = new File(Folder.temp.fsName + "\\" + "tmp.asl");
tmp_file.remove();
var tmp_name = Number(Math.random().toString().substr(2)).toString(36);
// create tmp style from layer style
var d = new ActionDescriptor();
var r = new ActionReference();
r.putClass(stringIDToTypeID("style"));
d.putReference(stringIDToTypeID("null"), r);
d.putString(stringIDToTypeID("name"), tmp_name);
var r1 = new ActionReference();
r1.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
d.putReference(stringIDToTypeID("using"), r1);
d.putBoolean(stringIDToTypeID("blendOptions"), true);
d.putBoolean(stringIDToTypeID("layerEffects"), false);
d.putBoolean(stringIDToTypeID("pushToDesignLibraries"), false);
executeAction(stringIDToTypeID("make"), d, DialogModes.NO);
// find index of last style
for (var i = 1;;i++)
{
var d = new ActionDescriptor();
var r = new ActionReference();
r.putIndex(stringIDToTypeID("style"), i);
d.putReference(stringIDToTypeID("null"), r);
try { executeAction(stringIDToTypeID("select"), d, DialogModes.NO); } catch (e) { --i; break; }
}
// save last style to tmp file
var d = new ActionDescriptor();
d.putPath(stringIDToTypeID("null"), tmp_file);
var list = new ActionList();
var r = new ActionReference();
r.putIndex(stringIDToTypeID("style"), i);
list.putReference(r);
d.putList(stringIDToTypeID("to"), list);
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);
// delete tmp style
var d = new ActionDescriptor();
var r = new ActionReference();
r.putIndex(stringIDToTypeID("style"), i);
d.putReference(stringIDToTypeID("null"), r);
executeAction(stringIDToTypeID("delete"), d, DialogModes.NO);
// read tmp file and extract style descriptor
tmp_file.open("r");
tmp_file.encoding = "BINARY";
var s = tmp_file.read();
tmp_file.close();
tmp_file.remove();
var i = s.indexOf(String.fromCharCode(0,0,0,16,0,0,0,1,0,0,0,0,0,0,0x53,0x74,0x79,0x6C))
var d = new ActionDescriptor();
d.fromStream(s.substr(i));
var d1 = new ActionDescriptor();
d1.putObject(stringIDToTypeID("object"), stringIDToTypeID("object"), d);
eval ("var obj=" + executeAction(stringIDToTypeID("convertJSONdescriptor"), d1).getString(stringIDToTypeID("json")));
alert(obj.toSource())
Copy link to clipboard
Copied
thats great, I came up to the same way - export to the layer style and parse it. Found some old post about it 3 years old. Looks like u combine style file and json in some tricky way. Can u comment last lines pls? starting from:
var i = s.indexOf(String.fromCharCode(0,0,0,16,0,0,0,1,0,0,0,0,0,0,0x53,0x74,0x79,0x6C))
...
I finally got that blends out. Use them all the time at work. Thank u one more time.