I have a PSD that contains 100s of layers. Most are grouped with individual elements within the groups (nested).
How do I Export to PNG certain individual groups (with nested layers inside of them)?
I don't want to run the Export All Layers to PNG Script, just need to export individual nested groups (layers) to PNG. I've found a few other 3rd party scripts, but they export everything. Only need to export the ones I've selected.
Thanks in advance
This script should do what you want. It works only when you have the group that you want selected (not a layer within that group) I've not extensively tested it and I'm assuming you don't have groups within groups (which becomes a headache)
// export png from group
srcDoc = app.activeDocument;
var allLayers = new Array();
var selectedLayer = srcDoc.activeLayer;
var theLayers = collectAllLayers(app.activeDocument, 0);
var groupName = "";
// function collect all layers
function collectAllLayers (theParent, level)
{
for (var m = theParent.layers.length - 1; m >= 0; m--)
{
var theLayer = theParent.layers[m];
// apply the function to layersets;
if (theLayer.typename == "LayerSet")
{
var goCode = false;
allLayers.push(level + theLayer.name);
groupName = theLayer.name
// alert(level + " " + theLayer.name)
collectAllLayers(theLayer, level + 1)
var subDoc = srcDoc.layers[m];
//alert(subDoc)
var numOfSubLayers = subDoc.layers.length;
//alert(numOfSubLayers)
for (var j = numOfSubLayers -1; j >= 0 ; j--)
{
if (subDoc.layers[j].typename == "ArtLayer")
{
// if the selected (active) layer is in the group
if (theLayer == selectedLayer)
{
var mylayerName = subDoc.layers[j].name
srcDoc.activeLayer = subDoc.layers[j];
// alert("Selected: " + mylayerName + " in " + groupName)
processLayer(mylayerName)
//selectAllLayersInGroup(groupName)
}
}
}
}
}
}
function processLayer(alayername)
{
// duplicate image into new document
// =======================================================
var id2784 = charIDToTypeID( "Mk " );
var desc707 = new ActionDescriptor();
var id2785 = charIDToTypeID( "null" );
var ref508 = new ActionReference();
var id2786 = charIDToTypeID( "Dcmn" );
ref508.putClass( id2786 );
desc707.putReference( id2785, ref508 );
var id2787 = charIDToTypeID( "Nm " );
desc707.putString( id2787, alayername );
var id2788 = charIDToTypeID( "Usng" );
var ref509 = new ActionReference();
var id2789 = charIDToTypeID( "Lyr " );
var id2790 = charIDToTypeID( "Ordn" );
var id2791 = charIDToTypeID( "Trgt" );
ref509.putEnumerated( id2789, id2790, id2791 );
desc707.putReference( id2788, ref509 );
executeAction( id2784, desc707, DialogModes.NO );
// create new layer
var layerRef = app.activeDocument.artLayers.add()
layerRef.name = "temp"
layerRef.blendMode = BlendMode.NORMAL
//merge visible
// =======================================================
var id1435 = charIDToTypeID( "MrgV" );
executeAction( id1435, undefined, DialogModes.NO );
// Set filePath and fileName to source path
filePath = srcDoc.path + '/' + app.activeDocument.name + '.png';
// save out the image
var pngFile = new File(filePath);
pngSaveOptions = new PNGSaveOptions();
pngSaveOptions.embedColorProfile = true;
pngSaveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
pngSaveOptions.matte = MatteType.NONE; pngSaveOptions.quality = 1;
activeDocument.saveAs(pngFile, pngSaveOptions, false, Extension.LOWERCASE);
// alert(filePath)
// close that save png
app.activeDocument.close()
// selects document that's been open the longest
app.activeDocument = srcDoc;
}
Related
Can anyone help how I can disable or enable the layer mask of the selected layer?
I wanted to automate it via scrip not with action.
I can't provide any code yet since I don't know yet what to do.
Scriptlistener is your friend here.
// Switch off any dialog boxes
displayDialogs = DialogModes.ERROR; // OFF
layermask(true);
alert("Layer mask enabled");
// or
layermask(false);
alert("Layer mask disabled");
// Switch back on any dialog boxes
displayDialogs = DialogModes.ALL; // ON
function layermask(bool)
{
// =======================================================
var idsetd = charIDToTypeID( "setd" );
var desc22 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref5 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref5.putEnumerated( idLyr, idOrdn, idTrgt );
desc22.putReference( idnull, ref5 );
var idT = charIDToTypeID( "T " );
var desc23 = new ActionDescriptor();
var idUsrM = charIDToTypeID( "UsrM" );
desc23.putBoolean( idUsrM, bool ); // value set here
var idLyr = charIDToTypeID( "Lyr " );
desc22.putObject( idT, idLyr, desc23 );
executeAction( idsetd, desc22, DialogModes.NO );
}
Using a bit of Action manager code to get the state of the layer mask we can use:
// Switch off any dialog boxes
displayDialogs = DialogModes.ERROR; // OFF
var layerMaskState = false;
s2t = stringIDToTypeID;
var r = new ActionReference();
r.putProperty(s2t('property'), s2t('userMaskEnabled'));
r.putEnumerated(s2t('layer'), s2t('ordinal'), s2t('targetEnum'));
// Make sure that the object that executeActionGet
// returns contains this key (which means the layer has a mask):
var d = executeActionGet(r);
if (d.hasKey(s2t('userMaskEnabled')))
{
layerMaskState = d.getBoolean(s2t('userMaskEnabled'));
}
// Toggle it!
layerMaskState = !layerMaskState;
layer_mask(layerMaskState);
// Switch off any dialog boxes
displayDialogs = DialogModes.ALL; // OFF
function layer_mask(bool)
{
// =======================================================
var idsetd = charIDToTypeID( "setd" );
var desc22 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref5 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref5.putEnumerated( idLyr, idOrdn, idTrgt );
desc22.putReference( idnull, ref5 );
var idT = charIDToTypeID( "T " );
var desc23 = new ActionDescriptor();
var idUsrM = charIDToTypeID( "UsrM" );
desc23.putBoolean( idUsrM, bool ); // set here
var idLyr = charIDToTypeID( "Lyr " );
desc22.putObject( idT, idLyr, desc23 );
executeAction( idsetd, desc22, DialogModes.NO );
}
As show in the image below,
How to get the width, height and rotation angle in Photoshop scripts.
Get Layer width, height and rotation angle
You need two things. First a function to grab the layer as a selection. Secondly, you need to get the layer bounds - from which you can work out the height and width.
var currentLayer = app.activeDocument.activeLayer.name;
var currentLayerSelection = layer_selection();
var lb = get_selection_bounds();
alert(currentLayer + " layer bounds:\n" + lb[0] + ", " + lb[1] + ", " + lb[2] + ", " + lb[3]);
// function GET SELECTION BOUNDS ()
// ----------------------------------------------------------------
function get_selection_bounds()
{
try
{
var x = parseFloat(app.activeDocument.selection.bounds[0]);
var y = parseFloat(app.activeDocument.selection.bounds[1]);
var x1 = parseFloat(app.activeDocument.selection.bounds[2]);
var y1 = parseFloat(app.activeDocument.selection.bounds[3]);
var selW = parseFloat(x1-x);
var selH = parseFloat(y1-y);
// return the results as an array
return [x, y, x1, y1];
}
catch(e)
{
alert("Oops " + e)
}
}
function layer_selection()
{
var id1268 = charIDToTypeID( "setd" );
var desc307 = new ActionDescriptor();
var id1269 = charIDToTypeID( "null" );
var ref257 = new ActionReference();
var id1270 = charIDToTypeID( "Chnl" );
var id1271 = charIDToTypeID( "fsel" );
ref257.putProperty( id1270, id1271 );
desc307.putReference( id1269, ref257 );
var id1272 = charIDToTypeID( "T " );
var ref258 = new ActionReference();
var id1273 = charIDToTypeID( "Chnl" );
var id1274 = charIDToTypeID( "Chnl" );
var id1275 = charIDToTypeID( "Trsp" );
ref258.putEnumerated( id1273, id1274, id1275 );
desc307.putReference( id1272, ref258 );
executeAction( id1268, desc307, DialogModes.NO )
}
You can work out the height and width:
var layerWidth = lb[2] - lb[0];
var layerHeight = lb[3] - lb[1];
alert("Width, height: " + layerWidth + ", " + layerHeight);
As for the angle.. Let's just say it's much easier to do that yourself.
Use the ruler tool - then Photoshop will work out the angle. Look in Image > Image Rotation > Arbitrary and it'll show you the angle to rotate the canvas to get it back to horizontal.
Is there any way or script to export layers composition to files with respect to artboards? I need the exported files to be named from artboards and suffix from the name of layer comps?
Thank you in advance, because I could not find a solution.
Here is your script. save it as any name.jsx and move it to your photoshops script Folder
It'll ask you for folder input and then will save it to appropriate folder with the name condition you said! Have fun :)
#target photoshop
var doc=app.activeDocument;
var artbrd=doc.layerSets;//return artboards as array
var lyrcmp=doc.layerComps;//return layercomps as array
var fldr = Folder.selectDialog ("Choose Save Location","");
var lyrcompname;
var artname;
for(var i=0;i<lyrcmp.length;i++){
var cmpname=lyrcmp[i].name;
lyrcompname = lyrcmp[i].name;
var idapplyComp = stringIDToTypeID( "applyComp" );
var desc353 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref75 = new ActionReference();
var idcompsClass = stringIDToTypeID( "compsClass" );
ref75.putName( idcompsClass, cmpname);
desc353.putReference( idnull, ref75 );
executeAction( idapplyComp, desc353, DialogModes.NO );
exportArtboard ();
}
function exportArtboard(){
for (var z=0;z<artbrd.length;z++){
artname=artbrd[z].name;
selectart();
cutpaste();
var saveFile = new File(fldr + "/" + artname + "_" + lyrcompname + ".jpg");
var saveOptions = new JPEGSaveOptions();
saveOptions.embedColorProfile = true;
saveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
saveOptions.matte = MatteType.NONE;
saveOptions.quality = 10;
app.activeDocument.saveAs(saveFile, saveOptions, true, Extension.LOWERCASE);
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
}
function cutpaste(){
cTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };
function Action2() {
// Set
function step1(enabled, withDialog) {
if (enabled != undefined && !enabled)
return;
var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putProperty(cTID('Chnl'), sTID("selection"));
desc1.putReference(cTID('null'), ref1);
desc1.putEnumerated(cTID('T '), cTID('Ordn'), cTID('Al '));
executeAction(cTID('setd'), desc1, dialogMode);
};
// Copy Merged
function step2(enabled, withDialog) {
if (enabled != undefined && !enabled)
return;
var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
executeAction(sTID('copyMerged'), undefined, dialogMode);
};
// Set
function step3(enabled, withDialog) {
if (enabled != undefined && !enabled)
return;
var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putProperty(cTID('Chnl'), sTID("selection"));
desc1.putReference(cTID('null'), ref1);
desc1.putEnumerated(cTID('T '), cTID('Ordn'), cTID('None'));
executeAction(cTID('setd'), desc1, dialogMode);
};
// Make
function step4(enabled, withDialog) {
if (enabled != undefined && !enabled)
return;
var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
desc2.putBoolean(sTID("artboard"), false);
desc2.putString(sTID("preset"), "Clipboard");
desc1.putObject(cTID('Nw '), cTID('Dcmn'), desc2);
desc1.putInteger(cTID('DocI'), 287);
executeAction(cTID('Mk '), desc1, dialogMode);
};
// Paste
function step5(enabled, withDialog) {
if (enabled != undefined && !enabled)
return;
var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
var desc1 = new ActionDescriptor();
desc1.putEnumerated(cTID('AntA'), cTID('Annt'), cTID('Anno'));
desc1.putClass(cTID('As '), cTID('Pxel'));
executeAction(cTID('past'), desc1, dialogMode);
};
step1(); // Set
step2(); // Copy Merged
step3(); // Set
step4(); // Make
step5(); // Paste
};
Action2.main = function () {
Action2();
};
Action2.main();
}
function selectart(){
cTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };
function select() {
// Select
function step1(enabled, withDialog) {
if (enabled != undefined && !enabled)
return;
var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putName(cTID('Lyr '), artname);
desc1.putReference(cTID('null'), ref1);
desc1.putBoolean(cTID('MkVs'), false);
var list1 = new ActionList();
list1.putInteger(8);
desc1.putList(cTID('LyrI'), list1);
executeAction(cTID('slct'), desc1, dialogMode);
};
step1(); // Select
};
select();
}
So I have 2 open documents with the same layer names.
I want to select a layer in the first document. Then run the script and automaticly select the same layer by name in the other document.
So far i've bin able to store the first layer name and open the 2nd document.
But I can't seem to set the same layer active.
This is my code:
var aDoc = app.activeDocument;
var AllDocs = app.documents;
var actLay = aDoc.activeLayer;
if (AllDocs.length > 1) {
var itemDoc = null;
var win = new Window("dialog","select the same name in other document");
this.windowRef = win;
win.Txt1 = win.add ("statictext", undefined, "Paste in which open document?");
win.NewList=win.add ("dropdownlist", undefined, AllDocs);
win.NewList.selection = 0;
itemDoc = win.NewList.selection.index;
win.testBtn4 = win.add('button', [260,140,100,50], 'select the same name in other document', {name:'doding1'});
win.testBtn4.onClick = dothing;
//Get selected document from list
win.NewList.onChange= function () {
itemDoc = win.NewList.selection.index;
return itemDoc;
}
//Show al items
win.show();
function dothing()
{
//Make the selected document the active document.
app.activeDocument = app.documents[itemDoc];
app.refresh();
//This outputs [Artlayer layername]
//alert (actLay);
//Find right layer and set active THIS DOES NOT WORK!!
//app.activeDocument.activeLayer = app.activeDocument.layers.itemByName(actLay);
win.close();
}
}
else
{
alert ("No other documents open");
}
Figured it out! Because the layer was in a certain group it couldn't find the layer.
fixed it with the following code:
activeDocument.activeLayer = activeDocument.layerSets[groupname].artLayers.getByName (actLay);
I got this from the adobe forum.
Someone wrote a function to find the location of the layer more easily.
//usage example:
select_layer(actLay.name);
function select_layer(id, add, viz)
{
try {
var d = new ActionDescriptor();
if (viz == undefined) viz = false;
var r = new ActionReference();
if (typeof(id) == "string") r.putName( charIDToTypeID( "Lyr " ), id);
else r.putIdentifier( charIDToTypeID( "Lyr " ), id);
d.putReference( charIDToTypeID( "null" ), r );
d.putBoolean( charIDToTypeID( "MkVs" ), viz );
if (add == true) d.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) );
if (add == -1) d.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "removeFromSelection" ) );
var ok = true;
try { executeAction( charIDToTypeID( "slct" ), d, DialogModes.NO ); } catch(e) { ok = false; }
d = null;
return ok;
}
catch (e) { alert(e); return false; }
}
I need to create a Photoshop script (I'm using Java Script) that takes a few images and applies the same mask to all of them.
(Here is what I mean by applying a mask)
Once I've loaded the images using this code
var sourceImageDoc = app.open(new File("./image.png"))
var maskImageDoc = app.open(new File("./mask.png"))
how I can set maskImageDoc to be the mask for sourceImageDoc?
Here is some snippets out of one of my scripts that works CS3 +. As you can see it uses the ugly script listener code - if you're applying it to a layer rather than a group, you may need to adjust that part? I'm not sure I remember ever using that function on a layer rather than a layerset.
//mask group to paper area
app.activeDocument.activeLayer = lyr;
selectRasterLayerContents();
app.activeDocument.activeLayer = grp;
AddMaskToGroup();
//Selects the contents of the active layer.
function selectRasterLayerContents() {
var id47 = charIDToTypeID( "setd" );
var desc11 = new ActionDescriptor();
var id48 = charIDToTypeID( "null" );
var ref11 = new ActionReference();
var id49 = charIDToTypeID( "Chnl" );
var id50 = charIDToTypeID( "fsel" );
ref11.putProperty( id49, id50 );
desc11.putReference( id48, ref11 );
var id51 = charIDToTypeID( "T " );
var ref12 = new ActionReference();
var id52 = charIDToTypeID( "Chnl" );
var id53 = charIDToTypeID( "Chnl" );
var id54 = charIDToTypeID( "Trsp" );
ref12.putEnumerated( id52, id53, id54 );
desc11.putReference( id51, ref12 );
executeAction( id47, desc11, DialogModes.NO );
}
//adds a mask revealing the selection to the active group
function AddMaskToGroup() {
var id42 = charIDToTypeID( "Mk " );
var desc8 = new ActionDescriptor();
var id43 = charIDToTypeID( "Nw " );
var id44 = charIDToTypeID( "Chnl" );
desc8.putClass( id43, id44 );
var id45 = charIDToTypeID( "At " );
var ref10 = new ActionReference();
var id46 = charIDToTypeID( "Chnl" );
var id47 = charIDToTypeID( "Chnl" );
var id48 = charIDToTypeID( "Msk " );
ref10.putEnumerated( id46, id47, id48 );
desc8.putReference( id45, ref10 );
var id49 = charIDToTypeID( "Usng" );
var id50 = charIDToTypeID( "UsrM" );
var id51 = charIDToTypeID( "RvlS" );
desc8.putEnumerated( id49, id50, id51 );
executeAction( id42, desc8, DialogModes.NO );
}
Applying a layer mask is a pain, because script listener won't hear it directly.
You'll want this then
function applyLayerMask()
{
var id1949 = charIDToTypeID( "Dlt " );
var desc398 = new ActionDescriptor();
var id1950 = charIDToTypeID( "null" );
var ref291 = new ActionReference();
var id1951 = charIDToTypeID( "Chnl" );
var id1952 = charIDToTypeID( "Chnl" );
var id1953 = charIDToTypeID( "Msk " );
ref291.putEnumerated( id1951, id1952, id1953 );
desc398.putReference( id1950, ref291 );
var id1954 = charIDToTypeID( "Aply" );
desc398.putBoolean( id1954, true );
executeAction( id1949, desc398, DialogModes.NO );
}
Here's my code to apply a layer mask to the currently selected object (provided it has a selection).
const layerMask = function () {
const makeID = stringIDToTypeID('make')
const newID = stringIDToTypeID('new')
const channelID = stringIDToTypeID('channel')
const atID = stringIDToTypeID('at')
const usingID = stringIDToTypeID('using')
const userMaskEnabledID = stringIDToTypeID('userMaskEnabled')
const revealSelectionID = stringIDToTypeID('revealSelection')
const actionDesc = new ActionDescriptor()
const actionRef = new ActionReference()
actionDesc.putClass(newID, channelID)
actionRef.putEnumerated(channelID, channelID, maskID)
actionDesc.putReference(atID, actionRef)
actionDesc.putEnumerated(usingID, userMaskEnabledID, revealSelectionID)
executeAction(makeID, actionDesc, DialogModes.NO)
}
Tested in Photoshop CC 2021
I'm late to the party, but here's my simple method for adding a mask to a layer in ExtendScript. The trick here is to place a copy of the mask just below the image, then merge the image into it. Note that the merge will destroy the original layer object and create a new one, so I always assign the result back to my original variable; otherwise it will become undefined.
// imageLayer: an artLayer in imageDoc that I want to mask
// maskLayer: an artLayer in maskDoc w/ just the mask to be added, no image data
// if both are in same file, you may not need the activeDocument assignments
app.activeDocument = maskDoc;
maskLayer.duplicate(imageLayer,ElementPlacement.PLACEAFTER);
app.activeDocument = imageDoc;
imageLayer = imageLayer.merge();
Now, this just adds the mask to the image layer non-destructively (i.e., it can be removed layer if you like). If you want to truly apply the mask (permanently conform the image to the mask while deleting the mask), then just duplicate a completely blank layer (no mask) below the masked merge-result from the first step above, and then merge that masked result one more time down into the blank layer.