Copy link to clipboard
Copied
Hi everybody,
I am a 3D Artist and working with Photoshop mainly to edit my renderings. Due to an update, I am now getting renderings with many different layers for the same thing, which I don't need. Unfortunately, I cannot switch them off in the renderer, so I either have to delete them by hand or what I thought would be very helpfull, if I could do it over a script or an action.
I was wondering if anyone of you has an idea, what would be the best way to do this. Let me just describe the process.
1.) I render a psd file which contains for example the following layers:
-flower
-flower_filter
-flower_alpha
-grass
-grass_filter
-grass_alpha
-sky
-sky_filter
-sky_alpha
background
The names and numbers of the layers can vary (although the group of 3 is always the same). I can name them any way I want. Only the background is a fixed name, which will always be the same.
I only need the layers "background" and the ones with the suffix "_alpha". So is there some way, to say, that all layers, except of "background" and "_alpha" will be deleted?
I would really appreciate any hints and help, as I am not 100% sure how to start.
Thanks a lot and have a nice evening
Copy link to clipboard
Copied
In a script you can get an array of the all the layers object. Them process the layers array delete layers that are not the background without a layer name the suffix _alpha. Only the bottom layer can be a background layer and there is a bit that indicated its a Background Layer a document could have many layers with the name Background. Layer Names need not be unique.
Copy link to clipboard
Copied
Method 1
Click layer "-flower", hold shift and click on layer "-sky_filter" to make a continuous selection of those layers. Then Ctrl click on the layers with named "alpha" to deselect them.
You now have the layer selected you want to delete, so click on the trash can icon bottom right of layers palette.
Method 2
Change Kind to Name, then input _alpha
Click folder icon to put these in a group
Change Name back to Kind
Select all layers except the layer group and background then delete layers.
Copy link to clipboard
Copied
Hello you two,
thanks a lot for you answer. Both methods are really good, although I am prefering the first one, as it seems, that this can be done through a script and I don't have to select at every new file the layers by hand.
Do you know some good resources for scripting in Photoshop? I am pretty new to this.
Have a nice evening and thanks a lot for you help.
Copy link to clipboard
Copied
This Forum....
There are some Samples and Tutorials on the Web Google search
This script may help you get started.
/* ==========================================================
// 2017 John J. McAssey (JJMack)
// ======================================================= */
// This script is supplied as is. It is provided as freeware.
// The author accepts no liability for any problems arising from its use.
// enable double-clicking from Mac Finder or Windows Explorer
#target photoshop // this command only works in Photoshop CS2 and higher
// bring application forward for double-click events
app.bringToFront();
// ensure at least one document open
if (!documents.length) alert('There are no documents open.', 'No Document');
else {
// declare Global variables
var allLayers = "";
//main(); // at least one document exists proceed
app.activeDocument.suspendHistory('Some Process Name','main()');
}
///////////////////////////////////////////////////////////////////////////////
// main function //
///////////////////////////////////////////////////////////////////////////////
function main() {
// declare local variables
var orig_ruler_units = app.preferences.rulerUnits;
var orig_type_units = app.preferences.typeUnits;
var orig_display_dialogs = app.displayDialogs;
app.preferences.rulerUnits = Units.PIXELS; // Set the ruler units to PIXELS
app.preferences.typeUnits = TypeUnits.POINTS; // Set Type units to POINTS
app.displayDialogs = DialogModes.NO; // Set Dialogs off
try { code(); }
// display error message if something goes wrong
catch(e) { alert(e + ': on line ' + e.line, 'Script Error', true); }
alert(allLayers);
app.displayDialogs = orig_display_dialogs; // Reset display dialogs
app.preferences.typeUnits = orig_type_units; // Reset ruler units to original settings
app.preferences.rulerUnits = orig_ruler_units; // Reset units to original settings
}
///////////////////////////////////////////////////////////////////////////////
// main function end //
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// The real code is embedded into this function so that at any point it can return //
// to the main line function to let it restore users edit environment and end //
/////////////////////////////////////////////////////////////////////////////////////
function code() {
processArtLayers(activeDocument)
}
function processArtLayers(obj) {
for( var i = obj.artLayers.length-1; 0 <= i; i--) {/* alert(obj.artLayers[i]); */processLayers(obj.artLayers[i])}
for( var i = obj.layerSets.length-1; 0 <= i; i--) {/* alert(obj.layerSets[i]); */processArtLayers(obj.layerSets[i])} // Process Layer Set Layers
}
function processLayers(layer) {
//alert('Layer Name = "' + layer.name + '" Layer Kind ' + layer.kind );
allLayers = allLayers + "ID " + layer.id + ", " + layer.name + ", " + layer.kind + "\n";
switch (layer.kind){
case LayerKind.SMARTOBJECT : processSmartObj(layer); break;
default : break; // none process layer types catch all
}
}
//////////////////////////////////////////////////////////////////////////////////
// Layer Type Functions //
//////////////////////////////////////////////////////////////////////////////////
function processSmartObj(obj) {
// alert('Smart Object = "' + obj.name + '"');
var localFilePath = "";
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), obj.id );
var desc = executeActionGet(ref);
//alert(actionDescriptor(desc));
var smObj = desc.getObjectValue(stringIDToTypeID('smartObject'));
//alert(actionDescriptor(smObj));
try {
//alert(obj_to_str(smObj), "Object Properties");
//var thePlace = smObj.getEnumerationType(stringIDToTypeID('place'));
var theDocumentID = smObj.getString(stringIDToTypeID('documentID'));
//var theCompsList = smObj.getObjectPropertyType(stringIDToTypeID('compsList'));
var theLinked = smObj.getBoolean(stringIDToTypeID("linked"));
var theFileReference = smObj.getString(stringIDToTypeID("fileReference"));
alert(["Smart Object Layer " + obj.name, "\n" + theDocumentID, "\nLinked=" + theLinked, "File='" + theFileReference + "'" ]);
}
catch(e) {alert(e);}
return localFilePath;
}
// Thanks to r-bin
function obj_to_str(obj){var str = ""; for (var p in obj) if(obj.hasOwnProperty(p))try{str+=p+"::"+obj[p]+"\n";}catch(e){};return str;}
// Thanks to SuperMerlin
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function actionDescriptor(desc){
if(desc.typename == 'ActionDescriptor'){
var c = desc.count;
var msg= "Action Descriptor Item Count = " + c;
for(var i=0;i<c;i++){ //enumerate descriptor's keys
//$.writeln('AD '+zeroPad( i+1, 2 )+' = '+IDTz(desc.getKey(i)) +' : '+desc.getType(desc.getKey(i)));
msg = msg + "\n" + 'AD '+zeroPad( i+1, 2 )+' = '+IDTz(desc.getKey(i)) +' : '+desc.getType(desc.getKey(i)) ;
}
return msg;
}
function IDTz(id){
try {
var res = typeIDToStringID( id );
if(res == '' ){
var res = typeIDToCharID( id );
}
}
catch(e){}
return res;
}
function zTID( s ){
if( s.length == 4 ) var res = charIDToTypeID( s );
if( s.length > 4 ) var res = stringIDToTypeID( s );
return res;
}
function zeroPad(num,pad) {
var z = Math.pow(10,Number(pad))
return num <= z ? ((Number( num) + z).toString().substr(1)): num
}
};
Copy link to clipboard
Copied
I'm a beginner in scripting, this is rather advanced I'm afraid. I know what I want to do, however, after many hours of dead ends I have nothing. Looking forward to seeing how this will be handled!
Copy link to clipboard
Copied
Try this, as long as your layer stacking pattern is as described it should work:
/*
https://community.adobe.com/t5/photoshop/deleting-layers-with-a-special-suffix/m-p/11772325
Deleting layers with a special suffix
I really wanted to select layers using a regular expression:
/^((?!_alpha|Background).)*$/igm
However, I ended up writing a script based on the very specific layer stacking order pattern, which is far from ideal:
flower
flower_filter
flower_alpha *
grass
grass_filter
grass_alpha *
sky
sky_filter
sky_alpha *
Background
I believe that it gets the job done, even if it is inflexible and not the thing of beauty that I was hoping for...
*/
#target photoshop
// Layer count divided by 3, less 1
var layersLength = app.activeDocument.layers.length - 1;
var repeatValue = layersLength / 3 - 1;
//alert(repeatValue);
// Deselect all layers
app.runMenuItem(stringIDToTypeID('selectNoLayers'));
// Tidy up the first set of 3 layers
selectFrontLayer(false);
addSelectBackwardLayer(false);
removeSelectedLayers();
// Tidy up any remaining layer triplets
for (i = 0; i < repeatValue; i++) {
repeatSteps();
}
// Here be functions
function removeSelectedLayers() {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var list = new ActionList();
var reference = new ActionReference();
reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
descriptor.putReference(c2t("null"), reference);
list.putInteger(14);
list.putInteger(15);
descriptor.putList(s2t("layerID"), list);
executeAction(s2t("delete"), descriptor, DialogModes.NO);
}
function selectFrontLayer(makeVisible) {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var list = new ActionList();
var reference = new ActionReference();
reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("front"));
descriptor.putReference(c2t("null"), reference);
descriptor.putBoolean(s2t("makeVisible"), makeVisible);
list.putInteger(15);
descriptor.putList(s2t("layerID"), list);
executeAction(s2t("select"), descriptor, DialogModes.NO);
}
function addSelectBackwardLayer(makeVisible) {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var list = new ActionList();
var reference = new ActionReference();
reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("backwardEnum"));
descriptor.putReference(c2t("null"), reference);
descriptor.putEnumerated(s2t("selectionModifier"), s2t("selectionModifierType"), s2t("addToSelection"));
descriptor.putBoolean(s2t("makeVisible"), makeVisible);
list.putInteger(14);
list.putInteger(15);
descriptor.putList(s2t("layerID"), list);
executeAction(s2t("select"), descriptor, DialogModes.NO);
}
function repeatSteps() {
select(false);
select2(false);
delete2();
function select(makeVisible) {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var list = new ActionList();
var reference = new ActionReference();
reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("backwardEnum"));
descriptor.putReference(c2t("null"), reference);
descriptor.putBoolean(s2t("makeVisible"), makeVisible);
list.putInteger(12);
descriptor.putList(s2t("layerID"), list);
executeAction(s2t("select"), descriptor, DialogModes.NO);
}
function select2(makeVisible) {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var list = new ActionList();
var reference = new ActionReference();
reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("backwardEnum"));
descriptor.putReference(c2t("null"), reference);
descriptor.putEnumerated(s2t("selectionModifier"), s2t("selectionModifierType"), s2t("addToSelection"));
descriptor.putBoolean(s2t("makeVisible"), makeVisible);
list.putInteger(11);
list.putInteger(12);
descriptor.putList(s2t("layerID"), list);
executeAction(s2t("select"), descriptor, DialogModes.NO);
}
function delete2() {
var c2t = function (s) {
return app.charIDToTypeID(s);
};
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var list = new ActionList();
var reference = new ActionReference();
reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
descriptor.putReference(c2t("null"), reference);
list.putInteger(11);
list.putInteger(12);
descriptor.putList(s2t("layerID"), list);
executeAction(s2t("delete"), descriptor, DialogModes.NO);
}
}
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html
Copy link to clipboard
Copied
I modified the script I posted to help you now to do what you want to do Keep the Background and Layers with a _alpha layer name suffix. Basically a one line function. Name this script "KeepBGandAlpha.jsx" I removed the code that was not needed and added one line.
if ( !layer.isBackgroundLayer & layer.name.indexOf("_alpha")==-1 ) layer.remove();
To complete the Script you need to add a Save see if you cans figure where that code needs to added and where you want to save and name the file for the modified document. If you save over the current document's backing file a programming error could destroy your documents.
/* ==========================================================
// 2017 John J. McAssey (JJMack)
// ======================================================= */
// This script is supplied as is. It is provided as freeware.
// The author accepts no liability for any problems arising from its use.
// enable double-clicking from Mac Finder or Windows Explorer
#target photoshop // this command only works in Photoshop CS2 and higher
// bring application forward for double-click events
app.bringToFront();
// ensure at least one document open
if (!documents.length) alert('There are no documents open.', 'No Document');
else {
// declare Global variables
var allLayers = "";
//main(); // at least one document exists proceed
app.activeDocument.suspendHistory('Some Process Name','main()');
}
///////////////////////////////////////////////////////////////////////////////
// main function //
///////////////////////////////////////////////////////////////////////////////
function main() {
// declare local variables
var orig_ruler_units = app.preferences.rulerUnits;
var orig_type_units = app.preferences.typeUnits;
var orig_display_dialogs = app.displayDialogs;
app.preferences.rulerUnits = Units.PIXELS; // Set the ruler units to PIXELS
app.preferences.typeUnits = TypeUnits.POINTS; // Set Type units to POINTS
app.displayDialogs = DialogModes.NO; // Set Dialogs off
try { code(); }
// display error message if something goes wrong
catch(e) { alert(e + ': on line ' + e.line, 'Script Error', true); }
app.displayDialogs = orig_display_dialogs; // Reset display dialogs
app.preferences.typeUnits = orig_type_units; // Reset ruler units to original settings
app.preferences.rulerUnits = orig_ruler_units; // Reset units to original settings
}
///////////////////////////////////////////////////////////////////////////////
// main function end //
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// The real code is embedded into this function so that at any point it can return //
// to the main line function to let it restore users edit environment and end //
/////////////////////////////////////////////////////////////////////////////////////
function code() {
processArtLayers(activeDocument)
}
function processArtLayers(obj) {
for( var i = obj.artLayers.length-1; 0 <= i; i--) {processLayers(obj.artLayers[i])}
for( var i = obj.layerSets.length-1; 0 <= i; i--) {processArtLayers(obj.layerSets[i])}
}
function processLayers(layer) {
if ( !layer.isBackgroundLayer & layer.name.indexOf("_alpha")==-1 ) layer.remove();
}
Copy link to clipboard
Copied
Nice work JJMack, that indexOf is what I was trying to do via a regualr expression and getting nowhere.
Copy link to clipboard
Copied
The thing is that is not a perfect test. The string "-alpha" could be anywhere in the File name and not be a suffix and that layer would not be deleted. To do a proper job you may be able to use .lastIndexOf( "_alpha" ); and see if that value + the length of "_alpha" equaled the length of the layer name. that it is a suffix. But its their layer naming convention so what I coded will most likely be OK for their use. I'm dyslectic my eyes can not decipher a regular expression. So I did not even brother the learn the syntax rules for one. Any regular expression in my code would be a copy and past job,
Copy link to clipboard
Copied
For what it is worth, with a few more months of experience the regular expression method came easy to me (regex was not the problem, the JS syntax was):
/*
Delete level based on first name
https://community.adobe.com/t5/photoshop/delete-level-based-on-first-name/td-p/12062329
*/
#target photoshop
function main() {
// Call the function to process layers/layerSets
processLayersAndSets(app.activeDocument);
function processLayersAndSets(target) {
// Loop through all layers
for (var l = target.artLayers.length - 1; 0 <= l; l--) {
// Call the removeLayer function
removeLayer(target.artLayers[l]);
}
// Loop through all layer groups/sets
for (var s = target.layerSets.length - 1; 0 <= s; s--) {
// Call the removeLayer function
processLayersAndSets(target.layerSets[s]);
}
// Remove non-background layers beginning with the word "test", case insensitive
function removeLayer(layer) {
if (!layer.isBackgroundLayer & layer.name.match(/^test\b/i) !== null) layer.remove();
}
}
}
app.activeDocument.suspendHistory("Run script", "main()");