Copy link to clipboard
Copied
Hard question for experts.
I can get list of linked layers, but how can I know if link is temporary disabled? (red cross)
it's cool!
It remains only to find out where you took the code for the command?
AM version:
...var r = new ActionReference();
r.putEnumerated(charIDToTypeID("capp"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var d = new ActionDescriptor();
d.putReference( charIDToTypeID( "null" ), r );
d.putString (stringIDToTypeID("command"), "getCommandEnabled");
d.putDouble(stringIDToTypeID("commandID"), 2960 );
var ret = executeAction(stringIDToTypeID("uiInfo"), d, DialogModes.NO).getObjectValue(str
Copy link to clipboard
Copied
I had the same dead end a few months ago:
Determining if the layer link is turned on or off
No answer, no solution.
PS is clearly not designed to be scripted.
Copy link to clipboard
Copied
I found workaround which could work
var idselectLinkedLayers = stringIDToTypeID( "selectLinkedLayers" );
var desc80 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref35 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref35.putEnumerated( idLyr, idOrdn, idTrgt );
desc80.putReference( idnull, ref35 );
executeAction( idselectLinkedLayers, desc80, DialogModes.NO );
1) read layers IDs of linked layers
2) run command selectedLinkedLayers
3) read IDs of selected layer
4) if list of IDs doesn't match it means that this layer or other layers link(s) is disabled
Copy link to clipboard
Copied
This workaround looks a bit better. In previous code you know that link group contains disabled link but you didn't know which one.
This uses availability of "select linked" menu item. I suggest modify this code to remember selected linked layers if code will have success. So you can skip all next layers in linked group.
isLinkDisabled();
function isLinkDisabled(){
try{
var idslct = charIDToTypeID( "slct" );
var desc135 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref63 = new ActionReference();
var idMn = charIDToTypeID( "Mn " );
var idMnIt = charIDToTypeID( "MnIt" );
var idplacedLayerEditContents = stringIDToTypeID( "selectLinkedLayers" );
ref63.putEnumerated( idMn, idMnIt, idplacedLayerEditContents );
desc135.putReference( idnull, ref63 );
executeAction( idslct, desc135, DialogModes.NO );
return true;
}catch(e){
if(e.number == -25920){ // menu item not available
return false;
}
throw e;
}
}
Copy link to clipboard
Copied
Jarda, thubs up!
This is not coding, this is the art of PS workaroundcomposing. Using layer menus plus a try/catch to watch if PS throws from the low level code snipplet.
Maybe this is THE way, PS supposed to be programmed.
Thanks!
Oliver
Copy link to clipboard
Copied
Well then, here's a more practical function if you use PS CC ))
alert(get_select_linked_eanbled())
function get_select_linked_eanbled()
{
try
{
var r = new ActionReference();
r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("menuBarInfo"));
r.putEnumerated(charIDToTypeID("capp"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var lst = executeActionGet(r).getObjectValue(stringIDToTypeID("menuBarInfo")).getList((stringIDToTypeID("submenu")))
for (var i = 0; i < lst.count; i++)
{
var obj = lst.getObjectValue(i);
if (obj.getString(stringIDToTypeID("title")) == "&Layer")
{
lst = obj.getList(stringIDToTypeID("submenu"));
for (var i = 0; i < lst.count; i++)
{
obj = lst.getObjectValue(i);
if (obj.getString(stringIDToTypeID("title")) == "&Select Linked Layers")
{
return obj.getBoolean(stringIDToTypeID("enabled"))
}
}
break;
}
}
}
catch (e) { alert(e); }
}
Copy link to clipboard
Copied
I just waited you come with something like it
Copy link to clipboard
Copied
r-bin: this will fail if user don't have photoshop in English. You should compare it according localized string. There should be way how to get this string localized in user language.
Copy link to clipboard
Copied
Indeed, in line 17th of r-bin code "&Layer" should be replaced by localize("$$$/Menu/Layer=&Layer") and in line 25th "&Select Linked Layers" by localize("$$$/Menu/Layer/SelectLinkedLayers=&Select Linked Layers") for non-English v.
Copy link to clipboard
Copied
Works fast. I tried it with 300 layer(Set)s of different kinds with different combinations. Of course that is no answer, because when you have big dimension then saving pixels of each layer to disk my take 1-2 secs for whole document. So it's probably good up to some layers limit (depending of its dimension). Possibly faltting before saving could help? Maybe later I'll try it...
with(psd = new PhotoshopSaveOptions()) {
layers = !(alphaChannels = embedColorProfile = annotations = spotColors = false)
}
activeDocument.saveAs(fle = File('~/desktop/.psd'), psd, true);
(function() {
fle.encoding = 'binary', fle.open('r'); var r = fle.read()
index = r.indexOf('8BIM\x040'), fle.seek(index + 10)
function bin(v) {return v * fle.readch().charCodeAt()}
var d = fle.read(L = l = bin(256) + bin(1)), re = /\x00/g
a = []; while(re.exec(d)) (a.push(re.lastIndex)), b = []
var r = r.slice(fle.tell(), r.length), re = /8BIMluni/g
while(a.length && re.exec(r)) {
if (a[0] + --l == L) {
b.push(re.lastIndex - 1), a.shift()
}
}
while(b.length) {
f = b.shift() + 9, w = ''
while(!r
) w += r[++f], ++f a.push(w)
}
fle.close(), fle.remove(), alert(a)
})()
I forgot to make case for not disabled layers so make sure you disabled at least one linked layer before you run this script
Copy link to clipboard
Copied
I am seeing you are improving in binary work. Anyway I think reading file binary should be last option when everything else fails 🙂
Copy link to clipboard
Copied
There's very small mistake in my script causing a crash when none of any Linked Layers was Disabled.
But it's easy to fix. At the end of line number 12 replace comma (,) to semicolon (;) right before b = []
Copy link to clipboard
Copied
I would use this instead:
#include Humanizer.jsx
// github.com/jardicc/ActionManagerHumanizer
// I don't have time rewrite it into pure Action manager code.
var $test = Humanizer.playObject("uiInfo", {
"null": {
"_enum": "ordinal",
"_ref": "application",
"_value": "targetEnum"
},
"command": "getCommandEnabled",
"commandID": 2960
});
alert($test.result.enabled);
In pure AM this should be faster because asking for whole menu structure is costly. There is huge amount of data.
ID should be static and it's localization independent and also no matter where it is located in menu.
Note: if you have already selected all linked layers then this command is disabled
Copy link to clipboard
Copied
it's cool!
It remains only to find out where you took the code for the command?
AM version:
var r = new ActionReference();
r.putEnumerated(charIDToTypeID("capp"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var d = new ActionDescriptor();
d.putReference( charIDToTypeID( "null" ), r );
d.putString (stringIDToTypeID("command"), "getCommandEnabled");
d.putDouble(stringIDToTypeID("commandID"), 2960 );
var ret = executeAction(stringIDToTypeID("uiInfo"), d, DialogModes.NO).getObjectValue(stringIDToTypeID("result")).getBoolean(stringIDToTypeID("enabled"));
alert(ret);
Copy link to clipboard
Copied
Command ID is inside menubar Descriptor.
Note: beware of commandIDs with negative value. They are not static but they are dynamic e.g. plugins, scripts ect.
Copy link to clipboard
Copied
Well, then still have to go over the "menuBarInfo"?
An interesting experience. Thank you!
P.S. In my code, it's better to replace putDouble with putInteger. So it is more correct.
Copy link to clipboard
Copied
Once you get this number I think you can hardcode it inside the code. It should be constant if a value is not negative.
The menubar is one option but you can get this number from script listener code. If you click on command in menu there will be 2 blocks of code. One of them looks like garbage and here is a number you want.
// =======================================================
var idinvokeCommand = stringIDToTypeID( "invokeCommand" );
var desc55 = new ActionDescriptor();
var idcommandID = stringIDToTypeID( "commandID" );
desc55.putInteger( idcommandID, 2960 ); // here is our ID
var idkcanDispatchWhileModal = stringIDToTypeID( "kcanDispatchWhileModal" );
desc55.putBoolean( idkcanDispatchWhileModal, true );
executeAction( idinvokeCommand, desc55, DialogModes.NO );
// =======================================================
var idselectLinkedLayers = stringIDToTypeID( "selectLinkedLayers" );
var desc56 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref17 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref17.putEnumerated( idLyr, idOrdn, idTrgt );
desc56.putReference( idnull, ref17 );
executeAction( idselectLinkedLayers, desc56, DialogModes.NO );
Copy link to clipboard
Copied
Few months ago when I needed to edit shortcuts in preferences (profiles you set in Photoshop) I found that is not possible by script, but I found other scriptable method. When opening a desired profile (that is a file with no extension) from for ex. C:\Users\User\AppData\Roaming\Adobe\Adobe Photoshop CS6\Adobe Photoshop CS6 Settings\WorkSpaces with XML by ExtendScript ToolKit, you'll get access to all id's and names plus shortcuts of commands. If you didn't use some shortcut in Ps then command won't be there displayed untill you save it in some profile, however build-in Photoshop commands have always the same (static) id's. I used this way of writing scripts in Adobe Bridge (however by static names for menu bars as it's all well described in Adobe Bridge JavaScript Reference) but I didn't suppose you have'll the same in Photoshop CC