• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

PS Scripting - check if layer link is temporary disabled

Enthusiast ,
Jul 22, 2017 Jul 22, 2017

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)

TOPICS
Actions and scripting

Views

3.3K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

People's Champ , Feb 22, 2018 Feb 22, 2018

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

...

Votes

Translate

Translate
Adobe
Contributor ,
Jul 22, 2017 Jul 22, 2017

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jul 23, 2017 Jul 23, 2017

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jul 23, 2017 Jul 23, 2017

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;

    }

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Jul 23, 2017 Jul 23, 2017

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Feb 22, 2018 Feb 22, 2018

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); }

    }

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 22, 2018 Feb 22, 2018

Copy link to clipboard

Copied

I just waited you come with something like it

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 22, 2018 Feb 22, 2018

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Jul 11, 2018 Jul 11, 2018

Copy link to clipboard

Copied

LATEST

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 21, 2018 Feb 21, 2018

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 22, 2018 Feb 22, 2018

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 🙂

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 20, 2018 May 20, 2018

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 = []

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 22, 2018 Feb 22, 2018

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Feb 22, 2018 Feb 22, 2018

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);

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 22, 2018 Feb 22, 2018

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.

2018-02-22_152030.jpg

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Feb 22, 2018 Feb 22, 2018

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 22, 2018 Feb 22, 2018

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 );

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 22, 2018 Feb 22, 2018

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines