Skip to main content
Known Participant
March 20, 2024
Answered

Link and relink mask by using script

  • March 20, 2024
  • 2 replies
  • 677 views

I having a trouble is this i have a scene with many layers that have mask, and i saw that photoshop dont allow me to unlink or disable mutiple layers at the same time ( even with the same kind of object(example: smart object). It there a way for me to disable, unlink or relink all of them at the same time.

This topic has been closed for replies.
Correct answer Stephen Marsh

@GiangHg999 

 

The following variation of the initial script will toggle linked to unlinked and vice versa!

 

/*
Toggle Layer Mask Link from Selected Layers.jsx
v1.0, 20th March 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/link-and-relink-mask-by-using-script/td-p/14502116
*/

#target photoshop

function main() {

    // Save the current dialog display settings
    var savedDisplayDialogs = app.displayDialogs;
    app.displayDialogs = DialogModes.NO;

    // Capture the initial layer visibility and layer selection
    var currentLayersState = getLayersVisiblity();

    // Get the selected layers: courtesy of jazz-y
    var s2t = stringIDToTypeID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var lrs = executeActionGet(r).getList(p),
        sel = new ActionReference();

    // Loop over the selected layers: courtesy of jazz-y
    for (var i = 0; i < lrs.count; i++) {
        sel.putIdentifier(s2t('layer'), p = lrs.getReference(i).getIdentifier(s2t('layerID')));
        (r = new ActionReference()).putIdentifier(s2t('layer'), p);
        (d = new ActionDescriptor()).putReference(s2t("target"), r);
        executeAction(s2t('select'), d, DialogModes.NO);

        // Special thanks to r-bin
        try {
            var id = activeDocument.activeLayer.id;
            var r = new ActionReference();
            r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("userMaskLinked"));
            r.putIdentifier(stringIDToTypeID("layer"), id);
            var getStatus = executeActionGet(r).getBoolean(stringIDToTypeID("userMaskLinked"));
            if (getStatus === true) {
                maskLinked(false);
            } else {
                maskLinked(true);
            }
        } catch (e) {}
    }
    // Finish the loop

    // Restore the initial layer visibility and selection
    setLayersVisiblity(currentLayersState);

    // Restore the dialogs
    app.displayDialogs = savedDisplayDialogs;
}

// Single history stage undo
activeDocument.suspendHistory("Toggle Layer Mask Link from Selected Layers", "main()");


///// FUNCTIONS /////

function hasLayerMask() {
    // From Adobe's Flatten All Masks.jsx
    var hasLayerMask = false;
    try {
        var ref = new ActionReference();
        var keyUserMaskEnabled = app.charIDToTypeID('UsrM');
        ref.putProperty(app.charIDToTypeID('Prpr'), keyUserMaskEnabled);
        ref.putEnumerated(app.charIDToTypeID('Lyr '), app.charIDToTypeID('Ordn'), app.charIDToTypeID('Trgt'));
        var desc = executeActionGet(ref);
        if (desc.hasKey(keyUserMaskEnabled)) {
            hasLayerMask = true;
        }
    } catch (e) {
        hasLayerMask = false;
    }
    return hasLayerMask;
}

function getLayersVisiblity() {
    // by jazz-y
    var s2t = stringIDToTypeID,
        t2s = typeIDToStringID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var targetLayers = executeActionGet(r).getList(p),
        seletion = [],
        visiblity = {};
    for (var i = 0; i < targetLayers.count; i++) seletion.push(targetLayers.getReference(i).getIdentifier());
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('numberOfLayers'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var len = executeActionGet(r).getInteger(p);
    for (var i = 1; i <= len; i++) {
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('layerSection'));
        r.putIndex(s2t('layer'), i);
        if (t2s(executeActionGet(r).getEnumerationValue(p)) == 'layerSectionEnd') continue;
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('layerID'));
        r.putIndex(s2t('layer'), i);
        var id = executeActionGet(r).getInteger(p);
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('visible'));
        r.putIndex(s2t('layer'), i);
        var visible = executeActionGet(r).getBoolean(p);
        visiblity[id] = visible;
    }
    return {
        selection: seletion,
        visiblity: visiblity
    };
}

function setLayersVisiblity(layersStateObject) {
    // by jazz-y
    var s2t = stringIDToTypeID;
    for (var a in layersStateObject.visiblity) {
        makeVisible = layersStateObject.visiblity[a] ? "show" : "hide";
        (r = new ActionReference()).putIdentifier(s2t('layer'), a);
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        executeAction(s2t(makeVisible), d, DialogModes.NO);
    }
    if (layersStateObject.selection.length) {
        var r = new ActionReference();
        for (var i = 0; i < layersStateObject.selection.length; i++)
            r.putIdentifier(s2t("layer"), layersStateObject.selection[i]);
        (d = new ActionDescriptor()).putReference(s2t("target"), r);
        d.putBoolean(s2t("makeVisible"), false);
        executeAction(s2t("select"), d, DialogModes.NO);
    } else {
        (r = new ActionReference()).putEnumerated(s2t("layer"), s2t('ordinal'), s2t('targetEnum'));
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        executeAction(s2t('selectNoLayers'), d, DialogModes.NO);
    }
}

function maskLinked(userMaskLinked) {
	var s2t = function (s) {
		return app.stringIDToTypeID(s);
	};
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();
	reference.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "targetEnum" ));
	descriptor.putReference( s2t( "null" ), reference );
	descriptor.putBoolean( s2t( "userMaskLinked" ), userMaskLinked ); // true or false
	descriptor.putObject( s2t( "to" ), s2t( "layer" ), descriptor );
	executeAction( s2t( "set" ), descriptor, DialogModes.NO );
}

 

2 replies

Stephen Marsh
Community Expert
Stephen MarshCommunity ExpertCorrect answer
Community Expert
March 20, 2024

@GiangHg999 

 

The following variation of the initial script will toggle linked to unlinked and vice versa!

 

/*
Toggle Layer Mask Link from Selected Layers.jsx
v1.0, 20th March 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/link-and-relink-mask-by-using-script/td-p/14502116
*/

#target photoshop

function main() {

    // Save the current dialog display settings
    var savedDisplayDialogs = app.displayDialogs;
    app.displayDialogs = DialogModes.NO;

    // Capture the initial layer visibility and layer selection
    var currentLayersState = getLayersVisiblity();

    // Get the selected layers: courtesy of jazz-y
    var s2t = stringIDToTypeID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var lrs = executeActionGet(r).getList(p),
        sel = new ActionReference();

    // Loop over the selected layers: courtesy of jazz-y
    for (var i = 0; i < lrs.count; i++) {
        sel.putIdentifier(s2t('layer'), p = lrs.getReference(i).getIdentifier(s2t('layerID')));
        (r = new ActionReference()).putIdentifier(s2t('layer'), p);
        (d = new ActionDescriptor()).putReference(s2t("target"), r);
        executeAction(s2t('select'), d, DialogModes.NO);

        // Special thanks to r-bin
        try {
            var id = activeDocument.activeLayer.id;
            var r = new ActionReference();
            r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("userMaskLinked"));
            r.putIdentifier(stringIDToTypeID("layer"), id);
            var getStatus = executeActionGet(r).getBoolean(stringIDToTypeID("userMaskLinked"));
            if (getStatus === true) {
                maskLinked(false);
            } else {
                maskLinked(true);
            }
        } catch (e) {}
    }
    // Finish the loop

    // Restore the initial layer visibility and selection
    setLayersVisiblity(currentLayersState);

    // Restore the dialogs
    app.displayDialogs = savedDisplayDialogs;
}

// Single history stage undo
activeDocument.suspendHistory("Toggle Layer Mask Link from Selected Layers", "main()");


///// FUNCTIONS /////

function hasLayerMask() {
    // From Adobe's Flatten All Masks.jsx
    var hasLayerMask = false;
    try {
        var ref = new ActionReference();
        var keyUserMaskEnabled = app.charIDToTypeID('UsrM');
        ref.putProperty(app.charIDToTypeID('Prpr'), keyUserMaskEnabled);
        ref.putEnumerated(app.charIDToTypeID('Lyr '), app.charIDToTypeID('Ordn'), app.charIDToTypeID('Trgt'));
        var desc = executeActionGet(ref);
        if (desc.hasKey(keyUserMaskEnabled)) {
            hasLayerMask = true;
        }
    } catch (e) {
        hasLayerMask = false;
    }
    return hasLayerMask;
}

function getLayersVisiblity() {
    // by jazz-y
    var s2t = stringIDToTypeID,
        t2s = typeIDToStringID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var targetLayers = executeActionGet(r).getList(p),
        seletion = [],
        visiblity = {};
    for (var i = 0; i < targetLayers.count; i++) seletion.push(targetLayers.getReference(i).getIdentifier());
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('numberOfLayers'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var len = executeActionGet(r).getInteger(p);
    for (var i = 1; i <= len; i++) {
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('layerSection'));
        r.putIndex(s2t('layer'), i);
        if (t2s(executeActionGet(r).getEnumerationValue(p)) == 'layerSectionEnd') continue;
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('layerID'));
        r.putIndex(s2t('layer'), i);
        var id = executeActionGet(r).getInteger(p);
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('visible'));
        r.putIndex(s2t('layer'), i);
        var visible = executeActionGet(r).getBoolean(p);
        visiblity[id] = visible;
    }
    return {
        selection: seletion,
        visiblity: visiblity
    };
}

function setLayersVisiblity(layersStateObject) {
    // by jazz-y
    var s2t = stringIDToTypeID;
    for (var a in layersStateObject.visiblity) {
        makeVisible = layersStateObject.visiblity[a] ? "show" : "hide";
        (r = new ActionReference()).putIdentifier(s2t('layer'), a);
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        executeAction(s2t(makeVisible), d, DialogModes.NO);
    }
    if (layersStateObject.selection.length) {
        var r = new ActionReference();
        for (var i = 0; i < layersStateObject.selection.length; i++)
            r.putIdentifier(s2t("layer"), layersStateObject.selection[i]);
        (d = new ActionDescriptor()).putReference(s2t("target"), r);
        d.putBoolean(s2t("makeVisible"), false);
        executeAction(s2t("select"), d, DialogModes.NO);
    } else {
        (r = new ActionReference()).putEnumerated(s2t("layer"), s2t('ordinal'), s2t('targetEnum'));
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        executeAction(s2t('selectNoLayers'), d, DialogModes.NO);
    }
}

function maskLinked(userMaskLinked) {
	var s2t = function (s) {
		return app.stringIDToTypeID(s);
	};
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();
	reference.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "targetEnum" ));
	descriptor.putReference( s2t( "null" ), reference );
	descriptor.putBoolean( s2t( "userMaskLinked" ), userMaskLinked ); // true or false
	descriptor.putObject( s2t( "to" ), s2t( "layer" ), descriptor );
	executeAction( s2t( "set" ), descriptor, DialogModes.NO );
}

 

Known Participant
March 21, 2024

Wow both codes work well. Your coding is excellent. Thank you sir! @Stephen Marsh 👌👌

Stephen Marsh
Community Expert
Community Expert
March 21, 2024

Haha, thank you, my coding is akin to playing with Lego! I often just arrange the bricks built by others.

Stephen Marsh
Community Expert
Community Expert
March 20, 2024

The following script will unlink the layer mask from all selected layers, generating a single history step:

 

/*
Unlink Layer Mask from Selected Layers.jsx
v1.0, 20th March 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/link-and-relink-mask-by-using-script/td-p/14502116
*/

#target photoshop

function main() {

    // Save the current dialog display settings
    var savedDisplayDialogs = app.displayDialogs;
    app.displayDialogs = DialogModes.NO;

    // Capture the initial layer visibility and layer selection
    var currentLayersState = getLayersVisiblity();

    // Get the selected layers: courtesy of jazz-y
    var s2t = stringIDToTypeID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var lrs = executeActionGet(r).getList(p),
        sel = new ActionReference();

    // Loop over the selected layers: courtesy of jazz-y
    for (var i = 0; i < lrs.count; i++) {
        sel.putIdentifier(s2t('layer'), p = lrs.getReference(i).getIdentifier(s2t('layerID')));
        (r = new ActionReference()).putIdentifier(s2t('layer'), p);
        (d = new ActionDescriptor()).putReference(s2t("target"), r);
        executeAction(s2t('select'), d, DialogModes.NO);

        // Raster mask, vector mask not currently supported
        if (hasLayerMask() === true) {
            // false to unlink, true to link
            maskLinked(false);
        } 
    }
    // Finish the loop

    // Restore the initial layer visibility and selection
    setLayersVisiblity(currentLayersState);

    // Restore the dialogs
    app.displayDialogs = savedDisplayDialogs;
}

// Single history stage undo
activeDocument.suspendHistory("Unlink Layer Mask from Selected Layers", "main()");


///// FUNCTIONS /////

function hasLayerMask() {
    // From Adobe's Flatten All Masks.jsx
    var hasLayerMask = false;
    try {
        var ref = new ActionReference();
        var keyUserMaskEnabled = app.charIDToTypeID('UsrM');
        ref.putProperty(app.charIDToTypeID('Prpr'), keyUserMaskEnabled);
        ref.putEnumerated(app.charIDToTypeID('Lyr '), app.charIDToTypeID('Ordn'), app.charIDToTypeID('Trgt'));
        var desc = executeActionGet(ref);
        if (desc.hasKey(keyUserMaskEnabled)) {
            hasLayerMask = true;
        }
    } catch (e) {
        hasLayerMask = false;
    }
    return hasLayerMask;
}

function getLayersVisiblity() {
    // by jazz-y
    var s2t = stringIDToTypeID,
        t2s = typeIDToStringID;
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var targetLayers = executeActionGet(r).getList(p),
        seletion = [],
        visiblity = {};
    for (var i = 0; i < targetLayers.count; i++) seletion.push(targetLayers.getReference(i).getIdentifier());
    (r = new ActionReference()).putProperty(s2t('property'), p = s2t('numberOfLayers'));
    r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
    var len = executeActionGet(r).getInteger(p);
    for (var i = 1; i <= len; i++) {
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('layerSection'));
        r.putIndex(s2t('layer'), i);
        if (t2s(executeActionGet(r).getEnumerationValue(p)) == 'layerSectionEnd') continue;
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('layerID'));
        r.putIndex(s2t('layer'), i);
        var id = executeActionGet(r).getInteger(p);
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('visible'));
        r.putIndex(s2t('layer'), i);
        var visible = executeActionGet(r).getBoolean(p);
        visiblity[id] = visible;
    }
    return {
        selection: seletion,
        visiblity: visiblity
    };
}

function setLayersVisiblity(layersStateObject) {
    // by jazz-y
    var s2t = stringIDToTypeID;
    for (var a in layersStateObject.visiblity) {
        makeVisible = layersStateObject.visiblity[a] ? "show" : "hide";
        (r = new ActionReference()).putIdentifier(s2t('layer'), a);
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        executeAction(s2t(makeVisible), d, DialogModes.NO);
    }
    if (layersStateObject.selection.length) {
        var r = new ActionReference();
        for (var i = 0; i < layersStateObject.selection.length; i++)
            r.putIdentifier(s2t("layer"), layersStateObject.selection[i]);
        (d = new ActionDescriptor()).putReference(s2t("target"), r);
        d.putBoolean(s2t("makeVisible"), false);
        executeAction(s2t("select"), d, DialogModes.NO);
    } else {
        (r = new ActionReference()).putEnumerated(s2t("layer"), s2t('ordinal'), s2t('targetEnum'));
        (d = new ActionDescriptor()).putReference(s2t('target'), r);
        executeAction(s2t('selectNoLayers'), d, DialogModes.NO);
    }
}

function maskLinked(userMaskLinked) {
	var s2t = function (s) {
		return app.stringIDToTypeID(s);
	};
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();
	reference.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "targetEnum" ));
	descriptor.putReference( s2t( "null" ), reference );
	descriptor.putBoolean( s2t( "userMaskLinked" ), userMaskLinked ); // true or false
	descriptor.putObject( s2t( "to" ), s2t( "layer" ), descriptor );
	executeAction( s2t( "set" ), descriptor, DialogModes.NO );
}

 

Simply change to maskLinked(true) to link the mask to selected layers.

 

It would be good to toggle the current state from linked to unlinked, or unlinked to linked... I'll take a look into that...