blackstallion
blackstallion

Reputation: 1

JS / JSX Script to generate unique PNGs from all permutations across all Photoshop Layer Groups and their Photoshop Layers

I'm looking into getting into generative art. My idea is to have Photoshop (CS5) generate a unique PNG for all permutations that exist while the script iterates through every LAYER across each LAYER GROUP (layerSets).

As an example, it would be similar to a character generator where: PARENT layerSets consist of parts or locations across the face/body (A,B) CHILD layers consist of accessories/styles (1,2,3) Such that all generated PNG permutations would be: A1B1,A2B1,A3B1;A2B1,A2B2,A2B3;A3B1,A3B2,A3B3 only. (A1A2, A2A3, A1A3; B1B2, B2B3, B1B3 are not necessary; Standalone A1,A2,A3,B1,B2,B3 are not necessary).

I've found some code from @Mr.Online that generates random, and potentially redundant combinations from user-inputted quantity. His script requires that all layers be hidden by the user prior to running.

Thanks so much. Hopefully this'll help:

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

Upvotes: 0

Views: 332

Answers (1)

Ghoul Fool
Ghoul Fool

Reputation: 6967

As you say, you need to ignore the random layers. However, if you know the number of layers & groups it's quite straight forward:

show_layers("A", "1");
show_layers("B", "1");

function show_layers(g, n)
{
    // g is the name of the group (layerset)
    // n is the name of the layer (artlayer)
    srcDoc.activeLayer = srcDoc.layerSets.getByName(g).artLayers.getByName(n);
    srcDoc.activeLayer.visible = true;
}

So, assuming all layers are switched off, you can get the layers by name and then make them visible.

Switching off all the layers is a bit more involved. You have to loop over all groups and then loop over its sublayers. Working with groups is a bit of a learning curve.

function switch_off_all_layers(bool)
{
  var numLayers = app.activeDocument.layers.length;

  // want to hide the background as well?
  // default: background = visible
  if (bool == undefined) bool = false;
  if (bool == false)
  {
    numLayers -=1; // -1 for background
  }

  for(var i = 0 ; i < numLayers; i++) 
  {
    if (app.activeDocument.layers[i].typename == "LayerSet")
    {
      app.activeDocument.layers[i].visible = true;

      var subDoc = app.activeDocument.layers[i];
      var numOfSubLayers = subDoc.layers.length;

      for (var j = numOfSubLayers -1; j >= 0; j--)
      {
        var tempSubLayer = subDoc.layers[j];
        tempSubLayer.visible = false;
      }
    }
  }
}

Further to my explanation, if you can't supply the group layers & names then you fill want to loop over all groups and all layers.

var groupLayers = [];
var artLayers = [];
var theLayers = collectAllLayers(app.activeDocument, 0);

alert("Group layers\n" + groupLayers);
alert("Art layers\n" + artLayers);

// 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 == "ArtLayer")
      {
        if (theLayer.isBackgroundLayer == true)
        {   
            // add background layer (if needed)
            // artLayers.push(theLayer.name);
        }
        else
        {
            // find the art layers
            artLayers.push(theLayer.name);
        }
      }
      else
      {
        // find the group layers
        groupLayers.push(theLayer.name);

        collectAllLayers(theLayer, level + 1)
      }
   }
}

Upvotes: 0

Related Questions