Photoshop action to make 1 random layer visible within each group - photoshop

I'm trying to use Photoshop actions to generate randomized images that are composed of a random sampling of layers. I have 3 groups of layers which are ALL not visible by default.
Within each group I'd like to make 1 random layer visible (in total there will be 3 "on" layers)
Export the whole thing as a .png file.
Repeat n times
Example Groups/Layers:
[FRUITS]
* [Apples]
* [Oranges]
* [Pears]
* [Bananas]
* [Kiwis]
[VEGGIES]
* [Asparagus]
* [Cilantro]
* [Eggplant]
[MEATS]
* [Beef]
* [Pork]
All layers are hidden by default, but when I play an action, I might get the following result (visible layers):
Image1: [Apples] [Eggplant] [Pork]
Image2: [Pears] [Asparagus] [Pork]
Image3: [Kiwis] [Cilantro] [Beef]

Here Is my script, but don't forget to do the following steps before running it:
Hide All Layers and Groups Except Background.
Save Your PSD.
Close and then reopen.
Now you are ready to rock.
Features
Make Unlimited Patterns you want from your groups.
Saved All Patterns As Indexed separate PNG in Separate Folder named PNG.
Watch GIF (below) to understand more:
function Visible() {
var Grps = app.activeDocument.layerSets; // loops through all groups
for(var i = 0; i < Grps.length; i++){
var tmp = app.activeDocument.layerSets[i].layers.length;
app.activeDocument.layerSets[i].visible=true;
var groupChildArr = app.activeDocument.layerSets[i].layers;
var randLays = Math.floor(Math.random() * tmp);
groupChildArr[randLays].visible = true;
Save();
}
Revert();
}
function Save() {
var outFolder = app.activeDocument; // psd name
var outPath = outFolder.path;
var fName = "PNG"; // define folder name
var f = new Folder(outPath + "/" + fName);
if ( ! f.exists ) {
f.create()
}
var saveFile = new File(outPath + "/" + fName +"/" + "Pattern_" + num + ".png");
pngSaveOptions = new PNGSaveOptions();
pngSaveOptions.interlaced = false;
app.activeDocument.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
}
// Original code - revert function does not work
// for some users
//function Revert(){
// var idslct = charIDToTypeID( "slct" );
// var desc300 = new ActionDescriptor();
// var idnull = charIDToTypeID( "null" );
// var ref163 = new ActionReference();
// var idSnpS = charIDToTypeID( "SnpS" );
// ref163.putName( idSnpS, "test.psd" );
// desc300.putReference( idnull, ref163 );
// executeAction( idslct, desc300, DialogModes.NO );
//}
function Revert(){
var idRvrt = charIDToTypeID( "Rvrt" );
executeAction( idRvrt, undefined, DialogModes.NO );
}
var count = prompt("How many patterns you want","");
for (var x=0 ; x<count;x++){
var num = x+1;
Visible();
}

Related

Photoshop Scripting: Relink Smart Object

I'm working on a script that should go through a photoshop document and relink all visible linked objects to a new specified file. I've gotten the loop working so that it cycles through every layer and collects only the visible layers, but for the life of me I can't find if there's a method available to relink a smart object. The closest I've found is this script:
https://gist.github.com/laryn/0a1f6bf0dab5b713395a835f9bfa805c
but when it gets to desc3.putPath(idnull, new File(newFile));, it spits out an error indicating that the functionality may not be present in the current Photoshop version. The script itself is 4 years old so it may be out of date.
Any help would be appreciated!
MY script as it stands is below:
// SELECT FILE //
var files = File.openDialog("Please select new linked file");
var selectedFile = files[0];
// GET ALL LAYERS //
var doc = app.activeDocument;
var allLayers = [];
var allLayers = collectAllLayers(doc, allLayers);
function collectAllLayers (doc, allLayers)
{
for (var m = 0; m < doc.layers.length; m++)
{
var theLayer = doc.layers[m];
if (theLayer.typename === "ArtLayer")
{
allLayers.push(theLayer);
}
else
{
collectAllLayers(theLayer, allLayers);
}
}
return allLayers;
}
// GET VISIBLE LAYERS //
var visibleLayers = [];
for (i = 0; i < allLayers.length; i++)
{
var layer = allLayers[i];
if (layer.visible && layer.kind == LayerKind.SMARTOBJECT)
{
visibleLayers.push(layer);
}
}
// REPLACE LAYERS
for (i = 0; i < visibleLayers.length; i++)
{
var layer = visibleLayers[i];
//--> REPLACE THE FILE HERE
}
Note: I am aware that this script currently may be error-prone if you don't know exactly how it works; I'm not intending to publish it at this time so I'm not super concerned with that at the moment. Mostly I just need the core functionality to work.
I used an AM function for getting visible smart objects — it works much faster. But if you want you can use yours. The important bit is relinkSO(path);: it'll also work in your script (just don't forget to select a layer: activeDocument.activeLayer = visibleLayers[i];)
Note that it works similar to Photoshop Relink to File command — if used on one instance of Smart Object all the instances are going to be relinked. If you want to relink only specific layers you'll have to break instancing first (probably using the New Smart Object via Copy command)
function main() {
var myFile = Folder.myDocuments.openDlg('Load file', undefined, false);
if (myFile == null) return false;
// gets IDs of all smart objects
var lyrs = getLyrs();
for (var i = 0; i < lyrs.length; i++) {
// for each SO id...
// select it
selectById(lyrs[i]);
// relink SO to file
relinkSO(myFile);
// embed linked if you want
embedLinked()
}
function getLyrs() {
var ids = [];
var layers, desc, vis, type, id;
try
{
activeDocument.backgroundLayer;
layers = 0;
}
catch (e)
{
layers = 1;
}
while (true)
{
ref = new ActionReference();
ref.putIndex(charIDToTypeID('Lyr '), layers);
try
{
desc = executeActionGet(ref);
}
catch (err)
{
break;
}
vis = desc.getBoolean(charIDToTypeID("Vsbl"));
type = desc.getInteger(stringIDToTypeID("layerKind"));
id = desc.getInteger(stringIDToTypeID("layerID"));
if (type == 5 && vis) ids.push(id);
layers++;
}
return ids;
} // end of getLyrs()
function selectById(id) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID('Lyr '), id);
desc.putReference(charIDToTypeID('null'), ref);
executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
} // end of selectById()
function relinkSO(path) {
var desc = new ActionDescriptor();
desc.putPath( charIDToTypeID('null'), new File( path ) );
executeAction( stringIDToTypeID('placedLayerRelinkToFile'), desc, DialogModes.NO );
} // end of relinkSO()
function embedLinked() {
executeAction( stringIDToTypeID('placedLayerConvertToEmbedded'), undefined, DialogModes.NO );
} // end of embedLinked()
}
app.activeDocument.suspendHistory("relink SOs", "main()");

Move layers to coordinates from text file - Photoshop scripting

I have a base layer - a map of Europe.
a bunch of "country" layers representing each country goes on top of the base layer.
I have a text file with the x/y coordinates of the top left corner of where each the country is to be placed, in relation to the base layer. The coordinates list is in pixel values separated with commas. And some of the values is negative as well.
So what I want to do is move each country layer according to the coordinate list.
Using Javascript I have been able to load the text file, but I am at a loss how to pass the coordinates to each layer and actually move the layers into place.
I cant seem to add a picture here or even a link - just get an error message.
Trying a hyper link: [Link to image][1]
Sergey Kritskiy , Ghoul Fool - Thank you for all your patience and help with this.
This is what I have for "Code" as of now - lots missing..
main();
var originalUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
function main(){
//declare listFile variable, prompt to browse for text file
var listFile = File.openDialog("Open list of coordinates","text(*.txt):*.txt;");
//if no file selected, return
if(listFile == null) return;
//read the selected text file (listFile) to a string(listString) - read coordinates from text File
listFile.open('r') ;
var listString = listFile.read();
listFile.close();
//splitting at line breaks, convert into array of strings
fileList = listString.split(' ');
//Need to tell what is X-value and what is Y-value
// call the source document
var srcDoc = app.activeDocument;
var numOfLayers = srcDoc.layers.length;
// main loop
for (var i = numOfLayers -1; i >= 0 ; i--)
{
//select that layer as you go along
srcDoc.activeLayer = srcDoc.artLayers[i];
// Here is where each layer should be paired to its coordinate from the text file - But how to do it?
// move the layer
moveLayer(moveX , moveY);
}
}
//iterate array of strings (coordinates), move layers acording to coordinates in the loaded text document
//for(var i=0; i<=fileList.length; i++){
// var theFile =new File(fileList[i]);
}
};```
[1]: https://www.mediafire.com/view/oms4kv7kt6l6zsf/coordinates_list_and_layers.JPG/file
Basically you want a function to translate a layer (from its original position to its intended position)
You'll also need to work in pixels, which'll make life easier.
You'll either have an object on an array of countries with their respective offsets.
Loop over all the layers. See if the layer name matches a country. It does? Then move that layer.
This'll give you a rough idea, but only works with maps from 1883 where Lichtenstein was the only known country in the world, which naturally made mapping easier.
var originalUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// call the source document
var srcDoc = app.activeDocument;
var numOfLayers = srcDoc.layers.length;
// main loop
for (var i = numOfLayers -1; i >= 0 ; i--)
{
//select that layer as you go along
srcDoc.activeLayer = srcDoc.artLayers[i];
if (srcDoc.artLayers[i].name == "Lichtenstein")
{
var moveX = 100;
var moveY = 40;
// move the layer
moveLayer(moveX , moveY);
}
}
// Put unit preferences back
app.preferences.rulerUnits = originalUnits;
// FUNCTION moveLayer (dx, dy) translates layer by dx, dy
function moveLayer(dx, dy)
{
// =======================================================
var id9297 = charIDToTypeID( "move" );
var desc2040 = new ActionDescriptor();
var id9298 = charIDToTypeID( "null" );
var ref1412 = new ActionReference();
var id9299 = charIDToTypeID( "Lyr " );
var id9300 = charIDToTypeID( "Ordn" );
var id9301 = charIDToTypeID( "Trgt" );
ref1412.putEnumerated( id9299, id9300, id9301 );
desc2040.putReference( id9298, ref1412 );
var id9302 = charIDToTypeID( "T " );
var desc2041 = new ActionDescriptor();
var id9303 = charIDToTypeID( "Hrzn" );
var id9304 = charIDToTypeID( "#Pxl" );
desc2041.putUnitDouble( id9303, id9304, dx );
var id9305 = charIDToTypeID( "Vrtc" );
var id9306 = charIDToTypeID( "#Pxl" );
desc2041.putUnitDouble( id9305, id9306, dy );
var id9307 = charIDToTypeID( "Ofst" );
desc2040.putObject( id9302, id9307, desc2041 );
executeAction( id9297, desc2040, DialogModes.NO );
}
So putting it all together you want something like this:
// Switch off any dialog boxes
displayDialogs = DialogModes.ERROR; // OFF
var originalUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
main();
function main()
{
//declare listFile variable, prompt to browse for text file
var listFile = File.openDialog("Open list of coordinates","text(*.txt):*.txt;");
//if no file selected, return
if(listFile == null) return;
//read the selected text file (listFile) to a string(listString) - read coordinates from text File
listFile.open('r') ;
var listString = listFile.read();
listFile.close();
//splitting at line breaks, convert into array of strings
fileList = listString.split("\n");
//Need to tell what is X-value and what is Y-value
// call the source document
var srcDoc = app.activeDocument;
var numOfLayers = srcDoc.layers.length;
// main loop
var c = 0;
// ignore the background? Start at numOfLayers -2
for (var i = numOfLayers -2; i >= 0 ; i--)
{
//select that layer as you go along
srcDoc.activeLayer = srcDoc.artLayers[i];
var theLayerName = srcDoc.artLayers[i].name;
var line = fileList[c].split(",");
var moveX = line[0];
var moveY = line[1];
// alert(theLayerName + " : " + moveX + ", " + moveY);
// Here is where each layer should be paired to its coordinate from the text file - But how to do it?
// move the layer
moveLayer(moveX , moveY);
// increment the file list counter
c+=1;
}
}
// set ruler units back to how it was
app.preferences.rulerUnits = originalUnits;
// Set Display Dialogs back to normal
displayDialogs = DialogModes.ALL; // NORMAL
// FUNCTION moveLayer (dx, dy) translates layer by dx, dy
function moveLayer(dx, dy)
{
// =======================================================
var id9297 = charIDToTypeID( "move" );
var desc2040 = new ActionDescriptor();
var id9298 = charIDToTypeID( "null" );
var ref1412 = new ActionReference();
var id9299 = charIDToTypeID( "Lyr " );
var id9300 = charIDToTypeID( "Ordn" );
var id9301 = charIDToTypeID( "Trgt" );
ref1412.putEnumerated( id9299, id9300, id9301 );
desc2040.putReference( id9298, ref1412 );
var id9302 = charIDToTypeID( "T " );
var desc2041 = new ActionDescriptor();
var id9303 = charIDToTypeID( "Hrzn" );
var id9304 = charIDToTypeID( "#Pxl" );
desc2041.putUnitDouble( id9303, id9304, dx );
var id9305 = charIDToTypeID( "Vrtc" );
var id9306 = charIDToTypeID( "#Pxl" );
desc2041.putUnitDouble( id9305, id9306, dy );
var id9307 = charIDToTypeID( "Ofst" );
desc2040.putObject( id9302, id9307, desc2041 );
executeAction( id9297, desc2040, DialogModes.NO );
}

Saving multiple files with group name Photoshop

My PSD structure
Group myname
layer -> Visible
Layer -> Hidden
Group 2randomname
layer -> Visible
Layer -> Hidden
and goes on ...
I am trying to save export groups as png, it works file when using file -> Exports -> Layers to File but my problem is its not using the group name, I want to include group name for each file, this is working when selecting all the groups and right click -> export as then selecting PNG the layers have the group names but the problem is its automatically trimming the canvas and there is no option to avoid trimming.
Is there any code or script that can do this ? any directions or help appreciated.
I guess something like this?
Result:
function main()
{
var topLayers = activeDocument.layers, // will export all top level layers (groups, backgorund layer, etc)
exportFolder = Folder.selectDialog();
if (exportFolder == null) return false;;
for (var i = 0; i < topLayers.length; i++)
{
activeDocument.activeLayer = topLayers[i];
toggleVisibility();
savePng24(topLayers[i].name);
toggleVisibility();
}
function savePng24(fileName)
{
var pngOpts = new ExportOptionsSaveForWeb;
pngOpts.format = SaveDocumentType.PNG
pngOpts.PNG8 = false;
pngOpts.transparency = true;
activeDocument.exportDocument(new File(exportFolder + "/" + fileName + ".png"), ExportType.SAVEFORWEB, pngOpts);
}; // end of savePng24()
function toggleVisibility()
{
var desc = new ActionDescriptor();
var list = new ActionList();
var ref = new ActionReference();
ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID('Trgt'));
list.putReference(ref);
desc.putList(cTID('null'), list);
desc.putBoolean(cTID('TglO'), true);
executeAction(cTID('Shw '), desc, DialogModes.NO);
}; // end of toggleVisibility()
function cTID(s)
{
return app.charIDToTypeID(s);
};
function sTID(s)
{
return app.stringIDToTypeID(s);
};
}
app.activeDocument.suspendHistory("temp", "main()");

Replacing smart objects in bulk with Photoshop

Just facing this issue: I have a mockup in Photoshop with two smart-objects: Rectangle 14.psb and Place your logo.psb
I have 100+ images in png that should be applied to create mockups.
For this reason, I would like your help to create a script that:
Let me select the png file that I would like to use
Open the smart objects (Rectangle 14.psb and Place your logo.psb)
Re-Link the same png to the layers "place your logo" of both the smart objects.
Finally, the script should save the file as png with the same file name of the selected png file adding just _new after its name.
So far I have tried this code without any luck:
#target photoshop
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var theName = myDocument.name.match(/(.*)\.[^\.]+$/)[1];
var thePath = myDocument.path;
var theLayer = myDocument.activeLayer;
// PSD Options;
psdOpts = new PhotoshopSaveOptions();
psdOpts.embedColorProfile = true;
psdOpts.alphaChannels = true;
psdOpts.layers = true;
psdOpts.spotColors = true;
// Check if layer is SmartObject;
if (theLayer.kind != "LayerKind.SMARTOBJECT") {
alert("selected layer is not a smart object")
} else {
// Select Files;
if ($.os.search(/windows/i) != -1) {
var theFiles = File.openDialog("please select files",
"*.psd;*.tif;*.jpg;*.png", true)
} else {
var theFiles = File.openDialog("please select files", getFiles,
true)
};
if (theFiles) {
for (var m = 0; m < theFiles.length; m++) {
// Replace SmartObject
theLayer = replaceContents(theFiles[m], theLayer);
var theNewName = theFiles[m].name.match(/(.*)\.[^\.]+$/)[1];
// Save JPG
myDocument.saveAs((new File(thePath + "/" + theName + "_" +
theNewName + ".psd")), psdOpts, true);
}
}
}
};
// Get PSDs, TIFs and JPGs from files
function getFiles(theFile) {
if (theFile.name.match(/\.(psd|png|jpg)$/i) != null ||
theFile.constructor.name == "Folder") {
return true
};
};
// Replace SmartObject Contents
function replaceContents(newFile, theSO) {
app.activeDocument.activeLayer = theSO;
// =======================================================
var idplacedLayerReplaceContents =
stringIDToTypeID("placedLayerReplaceContents");
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
desc3.putPath(idnull, new File(newFile));
var idPgNm = charIDToTypeID("PgNm");
desc3.putInteger(idPgNm, 1);
executeAction(idplacedLayerReplaceContents, desc3, DialogModes.NO);
return app.activeDocument.activeLayer
};
The above code substitute the smart object but I would like just to re-link the layer withing the smartobject to a new image and save the file. Any help would be much appreciated!
Are you familiar with Scriptlistener? You can use it to get all the functions you need and then modify the output to run within your loop of 100 pngs, it should be straightforward.

Photoshop Script for Smart Objects out of fixed folder

sorry for my not so good English, I hope you guys will understand what my problem is.. I don´t know really much about coding.
I have got the following code which allows to choose files that have to be changed in a smartobject in a psd document. I would like to have the code choose from a fixed folder like
../Desktop/Alldesigns
without asking which files I want to proceed.
I hope someone can help me...
#target photoshop
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var theName= myDocument.name.match(/(.*)\.[^\.]+$/)[1];
var thePath = myDocument.path;
var theLayer = myDocument.activeLayer;
// jpg options;
var jpgopts = new JPEGSaveOptions();
jpgopts.embedProfile = true;
jpgopts.formatOptions = FormatOptions.STANDARDBASELINE;
jpgopts.matte = MatteType.NONE;
jpgopts.quality = 9;
// check if layer is smart object;
if (theLayer.kind != "LayerKind.SMARTOBJECT") {alert ("selected layer is not a smart object")}
else {
// select files;
if ($.os.search(/windows/i) != -1) {var theFiles = File.openDialog ("please select files", "*.psd;*.tif;*.jpg", true)}
else {var theFiles = File.openDialog ("please select files", getFiles, true)};
if (theFiles) {
// work through the array;
for (var m = 0; m < theFiles.length; m++) {
// replace smart object;
theLayer = replaceContents (theFiles[m], theLayer);
var theNewName = theFiles[m].name.match(/(.*)\.[^\.]+$/)[1];
//save jpg;
myDocument.saveAs((new File(thePath+"/"+theNewName+"-"+theName+".jpg")),jpgopts,true);
}
}
}
};
////// get psds, tifs and jpgs from files //////
function getFiles (theFile) {
if (theFile.name.match(/\.(psd|tif)$/i) != null || theFile.constructor.name == "Folder") {
return true
};
};
////// replace contents //////
function replaceContents (newFile, theSO) {
app.activeDocument.activeLayer = theSO;
// =======================================================
var idplacedLayerReplaceContents = stringIDToTypeID( "placedLayerReplaceContents" );
var desc3 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
desc3.putPath( idnull, new File( newFile ) );
var idPgNm = charIDToTypeID( "PgNm" );
desc3.putInteger( idPgNm, 1 );
executeAction( idplacedLayerReplaceContents, desc3, DialogModes.NO );
return app.activeDocument.activeLayer
};
Best wishes from Germany
olee