4 Replies Latest reply on Sep 2, 2015 8:35 AM by c.pfaffenbichler

    Script I made: Instancer

    EnsilZah_ Level 1

      Hey, I had some downtime at work so I decided to write this script I would have liked to have a few times in the past, and I thought I'd share it if anyone might find it useful or have any suggestions.

       

      What it does is take a group of layers and places a copy of the layer on each count item null you've placed in the document.

      I'm thinking of adding some companion scripts later for stuff like various ways to distribute the count items on the document, like based on existing layers, randomly, in a grid, so it will be a sort of primitive particle system of sorts.

       

      Explained.png

       

      Code

      #target photoshop

       

       

      var scriptName = "NinjaScripts Instancer";

      var scriptVersion = "0002";

       

       

      //Suspends history while running script to undo results in one step.

      activeDocument.suspendHistory("NS_Instancer", "main()")

       

       

      function main()

      {

          if (activeDocument.countItems.length == 0) {alert ("Please use the Count Tool to designate instance positions"); return;}

          if (activeDocument.layerSets.length == 0) {alert ("Error, document doesn't contain any layer groups"); return;}

          OpenMainWindow();

      }

       

       

      //Iterates over count items list and places a random layer from the srcLayerset at its location

      function runInstancer(srcLayerset, destLayerset)

      {

          for (var i = 0; i < activeDocument.countItems.length; i++)

          {

              var randomIndex = getRandomInt(0, srcLayerset.artLayers.length-1)

              var newLayer = srcLayerset.artLayers[randomIndex].duplicate (destLayerset, ElementPlacement.INSIDE)

              translateLayerTo(newLayer,activeDocument.countItems[i].position[0],activeDocument.countIt ems[i].position[1]);

          }

      }

       

       

      //Generates a random integer between min and max

      function getRandomInt(min, max)

      {

          return Math.floor(Math.random() * (max - min + 1)) + min;

      }

       

       

      // returns the center of a layer's bounding box

      function getCenter(inLayer)

      {

          var Pivot = new Array();

          Pivot[0] = (inLayer.bounds[2] + inLayer.bounds[0])/2;

          Pivot[1] = (inLayer.bounds[3] + inLayer.bounds[1])/2;

          return Pivot

      }

       

       

      //translates a layer to a specific point

      function translateLayerTo (inLayer, inX, inY)

      {

          var layerPivot = getCenter(inLayer)

          inLayer.translate(-(layerPivot[0] - inX), -(layerPivot[1] -inY));

      }

       

       

      //Main interface wi

      function OpenMainWindow()

      {

          var MainWindow = new Window("dialog", scriptName + " v" + scriptVersion);

        

          MainWindow.orientation = 'column';

          MainWindow.alignChildren = 'center';

        

          var InputGroup = MainWindow.add("group");

          InputGroup.orientation = 'row';

        

              InputGroup.add("statictext", undefined, "Source sprite group:");

              var LayersetsDropdown = InputGroup.add("dropdownlist");

              LayersetsDropdown.preferredSize.width = 200;

              for (var i = 0; i < activeDocument.layerSets.length; i++)

              {

                  LayersetsDropdown.add("item",activeDocument.layerSets[i].name);

              }

              LayersetsDropdown.selection = 0;

       

          ConfirmGroup = MainWindow.add("group");

          ConfirmGroup.orientation = 'row';

              OkButton = ConfirmGroup.add("button", undefined, "Ok");

              OkButton.onClick = function()

              {

                      var srcLayerset = activeDocument.layerSets[LayersetsDropdown.selection.index];

                      if (srcLayerset.artLayers.length == 0) {alert ("Error, group contains no layers"); return;}

                      var newLayerset = activeDocument.layerSets.add();

                      newLayerset.name = "NSInstancer Layers";

                      runInstancer(srcLayerset, newLayerset);

                      MainWindow.close();

              }

       

       

              CancelButton = ConfirmGroup.add("button", undefined, "Cancel");

            

          MainWindow.center();

        var result = MainWindow.show();

       

       

      }

        • 1. Re: Script I made: Instancer
          c.pfaffenbichler Level 9

          If you change the translating function to Action Manager code you might get a significant speed improvement.

          1 person found this helpful
          • 2. Re: Script I made: Instancer
            c.pfaffenbichler Level 9

            And if you consolidate the duplication and offset into one AM function and address the layer by ID there may be further speed gains. (edited)

            if (app.documents.length > 0) {
            // get active layer’s index;
            var ref = new ActionReference();
            ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("layerID"));
            ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
            var layerDesc = executeActionGet(ref);
            var theID = layerDesc.getInteger(stringIDToTypeID("layerID"));
            // copy and transform;
            duplicateMoveRotateScale (theID, 0, 0, 100, 100, 15);
            duplicateMoveRotateScale (theID, 0, 0, 100, 100, 30);
            duplicateMoveRotateScale (theID, 0, 0, 100, 100, 45)
            };
            ////// duplicate layer and move, rotate and scale it //////
            function duplicateMoveRotateScale (theID, theX, theY, theScaleX, theScaleY, theRotation) {
            //app.activeDocument.activeLayer = theLayer;
            try{
            // =======================================================
            var idslct = charIDToTypeID( "slct" );
                var desc13 = new ActionDescriptor();
                var idnull = charIDToTypeID( "null" );
                    var ref7 = new ActionReference();
                    var idLyr = charIDToTypeID( "Lyr " );
                    ref7.putIdentifier( idLyr, theID );
                desc13.putReference( idnull, ref7 );
                var idMkVs = charIDToTypeID( "MkVs" );
                desc13.putBoolean( idMkVs, false );
            executeAction( idslct, desc13, DialogModes.NO );
            // =======================================================
            var idTrnf = charIDToTypeID( "Trnf" );
                var desc10 = new ActionDescriptor();
                var idnull = charIDToTypeID( "null" );
                    var ref6 = new ActionReference();
                    var idLyr = charIDToTypeID( "Lyr " );
                    var idOrdn = charIDToTypeID( "Ordn" );
                    var idTrgt = charIDToTypeID( "Trgt" );
                    ref6.putEnumerated( idLyr, idOrdn, idTrgt );
                desc10.putReference( idnull, ref6 );
                var idFTcs = charIDToTypeID( "FTcs" );
                var idQCSt = charIDToTypeID( "QCSt" );
                var idQcsa = charIDToTypeID( "Qcsa" );
                desc10.putEnumerated( idFTcs, idQCSt, idQcsa );
                var idOfst = charIDToTypeID( "Ofst" );
                    var desc11 = new ActionDescriptor();
                    var idHrzn = charIDToTypeID( "Hrzn" );
                    var idPxl = charIDToTypeID( "#Pxl" );
                    desc11.putUnitDouble( idHrzn, idPxl, theX );
                    var idVrtc = charIDToTypeID( "Vrtc" );
                    var idPxl = charIDToTypeID( "#Pxl" );
                    desc11.putUnitDouble( idVrtc, idPxl, theY );
                var idOfst = charIDToTypeID( "Ofst" );
                desc10.putObject( idOfst, idOfst, desc11 );
                var idWdth = charIDToTypeID( "Wdth" );
                var idPrc = charIDToTypeID( "#Prc" );
                desc10.putUnitDouble( idWdth, idPrc, theScaleX );
                var idHght = charIDToTypeID( "Hght" );
                var idPrc = charIDToTypeID( "#Prc" );
                desc10.putUnitDouble( idHght, idPrc, theScaleY );
                var idAngl = charIDToTypeID( "Angl" );
                var idAng = charIDToTypeID( "#Ang" );
                desc10.putUnitDouble( idAngl, idAng, theRotation );
                var idIntr = charIDToTypeID( "Intr" );
                var idIntp = charIDToTypeID( "Intp" );
                var idbicubicAutomatic = stringIDToTypeID( "bicubicAutomatic" );
                desc10.putEnumerated( idIntr, idIntp, idbicubicAutomatic );
                var idCpy = charIDToTypeID( "Cpy " );
                desc10.putBoolean( idCpy, true );
            executeAction( idTrnf, desc10, DialogModes.NO );
            return app.activeDocument.activeLayer
            } catch (e) {}
            };
            
            
            1 person found this helpful
            • 3. Re: Script I made: Instancer
              EnsilZah_ Level 1

              Thanks, this code works much faster, but I've come across some strange behavior.

              The random values I generate in my runInstancerFaster function seem to repeat several times in a row.

              When I comment out the duplicateMoveRotateScale line and look at the generated random values they seem to return to expected random behavior.

              I can only guess AM code is executed in some multithreaded fashion that takes values generated at the same time for multiple runs of the function?

              So, any suggestions to overcoming this, other than pregenerating a list of random values?

               

              (Also as an aside, how do I make a code block on this forum?)

              DuplicateRandoms.png

               

               

              Code

              #target photoshop

               

               

              var scriptName = "NinjaScripts Instancer";

              var scriptVersion = "0004";

               

               

              var sequentialNum = 0;

              //Suspends history while running script to undo results in one step.

              activeDocument.suspendHistory("NS_Instancer", "main()")

               

               

              function main()

              {

                  if (activeDocument.countItems.length == 0) {alert ("Please use the Count Tool to designate instance positions"); return;}

                  if (activeDocument.layerSets.length == 0) {alert ("Error, document doesn't contain any layer groups"); return;}

                  OpenMainWindow();

              }

               

               

              //Iterates over count items list and places a random layer from the srcLayerset at its location

              function runInstancerFaster(srcLayerset, destLayerset,distributionFunction,rotationRandom,scaleRandom)

              {

               

               

                 

                  for (var i = 0; i < activeDocument.countItems.length; i++)

                  {

                      Randoms.push(Math.random());

                      var randomIndex = distributionFunction(srcLayerset.artLayers.length);

                     

                      var layerPivot = getCenter(srcLayerset.artLayers[randomIndex]);

                          

                      var offsetX = -(layerPivot[0] - activeDocument.countItems[i].position[0]);

                      var offsetY = -(layerPivot[1] - activeDocument.countItems[i].position[1]);

                      var scaleX = 100 + (Math.random()*scaleRandom*getRandomSign())

                      var scaleY =scaleX

                      var rot = rotationRandom*Math.random()*getRandomSign();

                      var theID = getLayerID(srcLayerset.artLayers[randomIndex]);

                     

                      var newLayer = duplicateMoveRotateScale (theID, offsetX, offsetY, scaleX, scaleY, rot)

                      newLayer.move (destLayerset, ElementPlacement.INSIDE)

               

               

                  }

                  alert (Randoms);

              }

               

               

              //Generates a random integer between min and max

              function getRandomInt(min, max)

              {

                  return Math.floor(Math.random() * (max - min + 1)) + min;

              }

               

               

              function getRandomSign()

              {

                return (Math.random() >= 0.5)?1:-1;

              }

               

               

              // returns the center of a layer's bounding box

              function getCenter(inLayer)

              {

                  var Pivot = new Array();

                  Pivot[0] = (inLayer.bounds[2] + inLayer.bounds[0])/2;

                  Pivot[1] = (inLayer.bounds[3] + inLayer.bounds[1])/2;

                  return Pivot

              }

               

               

              //translates a layer to a specific point

              function translateLayerTo (inLayer, inX, inY)

              {

                  var layerPivot = getCenter(inLayer)

                  inLayer.translate(-(layerPivot[0] - inX), -(layerPivot[1] -inY));

              }

               

               

              //Main interface wi

              function OpenMainWindow()

              {

                  var MainWindow = new Window("dialog", scriptName + " v" + scriptVersion);

                 

                  MainWindow.orientation = 'column';

                  MainWindow.alignChildren = 'center';

                 

                  var InputGroup = MainWindow.add("group");

                  InputGroup.orientation = 'row';

                 

                      InputGroup.add("statictext", undefined, "Source sprite group:");

                      var LayersetsDropdown = InputGroup.add("dropdownlist");

                      LayersetsDropdown.preferredSize.width = 250;

                      for (var i = 0; i < activeDocument.layerSets.length; i++)

                      {

                          LayersetsDropdown.add("item",activeDocument.layerSets[i].name);

                      }

                      LayersetsDropdown.selection = 0;

                     

                      DistributionPanel = MainWindow.add("panel", undefined, "Distribution");

                      DistributionPanel.spacing = 0;

                      DistributionPanel.orientation = 'row';

                          DistributionPanel.add("statictext", undefined, "Random: ");

                          var radioRand = DistributionPanel.add("radiobutton")

                          radioRand.value = true;

                          DistributionPanel.add("statictext", undefined, "     Sequential: ");

                          var radioSeq = DistributionPanel.add("radiobutton")

                          radioRand.onClick = function(){radioSeq.value= false; radioRand.value = true;}

                          radioSeq.onClick = function(){radioSeq.value= true; radioRand.value = false;}           

                          DistributionPanel.add("statictext", undefined, "     Rotation Random: ");

                          var editRotation = DistributionPanel.add("edittext", undefined, "0");

                         

                          DistributionPanel.add("statictext", undefined, "°     Scale Random: ");

                          var editScale = DistributionPanel.add("edittext", undefined, "0");

                          DistributionPanel.add("statictext", undefined, "%");

                         

                     

               

                  ConfirmGroup = MainWindow.add("group");

                  ConfirmGroup.orientation = 'row';

                      OkButton = ConfirmGroup.add("button", undefined, "Ok");

                      OkButton.onClick = function()

                      {

                              function distRandom(inLength) {return getRandomInt(0, inLength-1)}

                              function distSequential(inLength) {var tmp = sequentialNum%inLength; sequentialNum = sequentialNum+1; return tmp;}

                              var srcLayerset = activeDocument.layerSets[LayersetsDropdown.selection.index];

                              if (srcLayerset.artLayers.length == 0) {alert ("Error, group contains no layers"); return;}

                              var newLayerset = activeDocument.layerSets.add();

                              newLayerset.name = "NSInstancer Layers";

                              runInstancerFaster(srcLayerset, newLayerset,((radioRand.value)?distRandom:distSequential), (isNaN(Number(editRotation.text))?0:Number(editRotation.text)),(isNaN(Number(editScale.te xt))?0:Number(editScale.text)));

                              MainWindow.close();

                      }

               

               

                      CancelButton = ConfirmGroup.add("button", undefined, "Cancel");

                     

                  MainWindow.center();

                var result = MainWindow.show();

               

               

              }

               

               

               

               

              function cID (inVal) { return charIDToTypeID(inVal);}

              function sID (inVal) { return stringIDToTypeID(inVal);}

               

               

              function getLayerID(inLayer)

              {

                  activeDocument.activeLayer = inLayer;

                  var ref = new ActionReference(); 

                  ref.putProperty(sID("property"), sID("layerID")); 

                  ref.putEnumerated( cID("Lyr "), cID("Ordn"), cID("Trgt") ); 

                  var layerDesc = executeActionGet(ref); 

                  return layerDesc.getInteger(sID("layerID")); 

              }

                 

              ////// duplicate layer and move, rotate and scale it ////// 

              function duplicateMoveRotateScale (theID, theX, theY, theScaleX, theScaleY, theRotation)

                  try

                  { 

                      var desc13 = new ActionDescriptor(); 

                      var ref7 = new ActionReference(); 

                      ref7.putIdentifier( cID( "Lyr " ), theID ); 

                      desc13.putReference( cID( "null" ), ref7 ); 

                      desc13.putBoolean( cID( "MkVs" ), false ); 

                      executeAction( cID( "slct" ), desc13, DialogModes.NO ); 

                      var desc10 = new ActionDescriptor(); 

                      var ref6 = new ActionReference(); 

                      ref6.putEnumerated( cID( "Lyr " ), cID( "Ordn" ), cID( "Trgt" ) ); 

                      desc10.putReference(  cID( "null" ), ref6 ); 

                      desc10.putEnumerated( cID( "FTcs" ), cID( "QCSt" ), cID( "Qcsa" ) ); 

                      var idOfst = cID( "Ofst" ); 

                      var desc11 = new ActionDescriptor(); 

                      desc11.putUnitDouble( cID( "Hrzn" ), cID( "#Pxl" ), theX ); 

                      desc11.putUnitDouble( cID( "Vrtc" ), cID( "#Pxl" ), theY ); 

                      desc10.putObject( cID( "Ofst" ), cID( "Ofst" ), desc11 ); 

                      desc10.putUnitDouble( cID( "Wdth" ), cID( "#Prc" ), theScaleX ); 

                      desc10.putUnitDouble( cID( "Hght" ), cID( "#Prc" ), theScaleY ); 

                      desc10.putUnitDouble( cID( "Angl" ), cID( "#Ang" ), theRotation ); 

                      desc10.putEnumerated( cID( "Intr" ), cID( "Intp" ), sID( "bicubicAutomatic" ) ); 

                      desc10.putBoolean( cID( "Cpy " ), true ); 

                      executeAction( cID( "Trnf" ), desc10, DialogModes.NO ); 

                      return app.activeDocument.activeLayer 

                      } catch (e) {alert("Error");} 

              }

              • 4. Re: Script I made: Instancer
                c.pfaffenbichler Level 9

                how do I make a code block on this forum?

                Click "Use advanced editor" and then …

                advancedEditorSyntaxHighlighting.jpg