Skip to main content
Tyler229371107i00
Participating Frequently
January 7, 2024
Answered

Script Needed - Convert to Color Fill

  • January 7, 2024
  • 3 replies
  • 1174 views

I'm bouncing from Photoshop to CSP and back to liquefy multiple layers at once since Photoshop can't do that. Certain layer features are lost in the conversion, one being color-fill layers. CSP converts them to a normal layer with any region revealed by the mask filled with a flat color.

I would like a script where I can click on that layer, and it will convert it back into a Color Fill Layer and delete the one CSP made. Can someone help me out? Thanks in advance.

(see attached image)

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

@Tyler229371107i00 

 

The following script will apply the last used liquify mesh to all layers and layer masks in a single pass!

 

/*
Liquify Selected Layers & Masks using Last Mesh.jsx
v1.0, 8th January 2024, Stephen Marsh
*/

#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) {
            // Apply the last liquify filter mesh to the layer mask
            selectLayerCompositeChannel("mask");
            applyLastMesh();
        } else {
            // Apply the last liquify filter mesh
            applyLastMesh();
        }
    }
    // Finish the loop

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

    // Restore the dialogs
    app.displayDialogs = savedDisplayDialogs;

    app.beep();
    alert("Script completed!");
}

// Single history stage undo
activeDocument.suspendHistory("Liquify Selected Layers & Masks using Last Mesh.jsx", "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 selectLayerCompositeChannel(chanPara) {
    // "RGB" | "mask"
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var reference = new ActionReference();
    reference.putEnumerated(s2t("channel"), s2t("channel"), s2t(chanPara));
    descriptor.putReference(s2t("null"), reference);
    descriptor.putBoolean(s2t("makeVisible"), false);
    executeAction(s2t("select"), descriptor, DialogModes.NO);
}

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 applyLastMesh() {
    var idLqFy = charIDToTypeID("LqFy");
    var desc213 = new ActionDescriptor();
    var idLqMD = charIDToTypeID("LqMD");
    desc213.putString(idLqMD, app.preferencesFolder.fsName + "/" + "Liquify Last Mesh.psp");
    executeAction(idLqFy, desc213, DialogModes.NO);
}

 

 

3 replies

Stephen Marsh
Community Expert
Stephen MarshCommunity ExpertCorrect answer
Community Expert
January 8, 2024

@Tyler229371107i00 

 

The following script will apply the last used liquify mesh to all layers and layer masks in a single pass!

 

/*
Liquify Selected Layers & Masks using Last Mesh.jsx
v1.0, 8th January 2024, Stephen Marsh
*/

#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) {
            // Apply the last liquify filter mesh to the layer mask
            selectLayerCompositeChannel("mask");
            applyLastMesh();
        } else {
            // Apply the last liquify filter mesh
            applyLastMesh();
        }
    }
    // Finish the loop

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

    // Restore the dialogs
    app.displayDialogs = savedDisplayDialogs;

    app.beep();
    alert("Script completed!");
}

// Single history stage undo
activeDocument.suspendHistory("Liquify Selected Layers & Masks using Last Mesh.jsx", "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 selectLayerCompositeChannel(chanPara) {
    // "RGB" | "mask"
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var reference = new ActionReference();
    reference.putEnumerated(s2t("channel"), s2t("channel"), s2t(chanPara));
    descriptor.putReference(s2t("null"), reference);
    descriptor.putBoolean(s2t("makeVisible"), false);
    executeAction(s2t("select"), descriptor, DialogModes.NO);
}

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 applyLastMesh() {
    var idLqFy = charIDToTypeID("LqFy");
    var desc213 = new ActionDescriptor();
    var idLqMD = charIDToTypeID("LqMD");
    desc213.putString(idLqMD, app.preferencesFolder.fsName + "/" + "Liquify Last Mesh.psp");
    executeAction(idLqFy, desc213, DialogModes.NO);
}

 

 

Tyler229371107i00
Participating Frequently
January 8, 2024

Stephen, this is insane. So if I'm understanding this correctly, there are three scripts as options here.

1 - Liquify layer contents for any selected layers

2 - Liquify mask contents for any selected layers

3 - Liquify layer and mask contents for any selected layers

Is that how it should work? =O

Stephen Marsh
Community Expert
Community Expert
January 8, 2024

You got it! As you requested for the 3rd script, if the layer has a mask, only the mask is liquified, not the layer.

Stephen Marsh
Community Expert
Community Expert
January 8, 2024

@Tyler229371107i00 

 

The following script can be run after the first script, it will liquify raster layer masks using the previously used mesh, ignoring the layer data which was previously liquified using the first script.

 

/*
Liquify Selected Layers Masks using Last Mesh.jsx
v1.0, 8th January 2024, Stephen Marsh
*/

#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) {
            // Select the mask
            selectLayerCompositeChannel("mask");
            // Apply the last liquify filter mesh
            var idLqFy = charIDToTypeID("LqFy");
            var desc213 = new ActionDescriptor();
            var idLqMD = charIDToTypeID("LqMD");
            desc213.putString(idLqMD, app.preferencesFolder.fsName + "/" + "Liquify Last Mesh.psp");
            executeAction(idLqFy, desc213, DialogModes.NO);
        }
    }
    // Finish the loop

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

    // Restore the dialogs
    app.displayDialogs = savedDisplayDialogs;

    app.beep();
    alert("Script completed!");
}

// Single history stage undo
activeDocument.suspendHistory("Liquify Selected Layers Masks using Last Mesh.jsx", "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 selectLayerCompositeChannel(chanPara) {
    // "RGB" | "mask"
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var reference = new ActionReference();
    reference.putEnumerated(s2t("channel"), s2t("channel"), s2t(chanPara));
    descriptor.putReference(s2t("null"), reference);
    descriptor.putBoolean(s2t("makeVisible"), false);
    executeAction(s2t("select"), descriptor, DialogModes.NO);
}

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

 

 

The final step will be to combine both scripts into one.

Tyler229371107i00
Participating Frequently
January 7, 2024

Alternatively, if someone can write a script to take a liquified edit and apply it to a selection of multiple layers, that would be an even better solution so I don't have to use CSP. Still, I've contacted a scripter before, and they said Adobe doesn't let you do that. I'm an artist, so I have no idea if that is true.

Stephen Marsh
Community Expert
Community Expert
January 8, 2024

You can use the last liquify mesh settings... Or save and load mesh settings from a .msh file. If working in the same session you can just reapply the previous Liquify to new layers which will automatically use the last mesh.

 

Tyler229371107i00
Participating Frequently
January 8, 2024

I should have assumed this would be suggested. This is too slow when dealing with hundreds of layers.