Move layer problem

Anyone, especially newbies, asking for help with Photoshop Scripting and Photoshop Automation - as opposed to those contributing to discussion about an aspect of Photoshop Scripting

Moderators: Tom, Kukurykus

Mike Hale

Move layer problem

Post by Mike Hale »

move will work with either a layer or a layerset. If the first argument is not correct you normally get a 'no such element' error or some other message about it not being a valid object. 'Illegal argument' error in this case means the wrong ElementPlacement constant was used.

If the relativeObject is a layerset you can only use ElementPlacement.INSIDE.

If the relativeObject is a layer you can use PLACEATBEGINNING, PLACEATEND, PLACEBEFORE, or PLACEAFTER depending on where you want the layer in relation to the relativeObject. PLACEATBEGINNING puts it at the top of the group or stack if top level. PLACEATEND puts it at the bottom of the group, etc. PLACEBEFORE and PLACEAFTER puts it above or below.

I sorry that I don't understand your layer layout enough to give you the exact code to do what you want.

Professional AI Audio Generation within Adobe Premiere Pro - Download Free Plugin here

paulemasters

Move layer problem

Post by paulemasters »

No need to be sorry. I am not sure what I am doing either , at least with the script.

However... I seem to have got it to work. I am not sure exactly how it works but for now it's good enough. Although I would like to place the moved item at the bottom of the layer set.

Here is the complete end of the script:
Code: Select all// Get documents - get target active layer
var buttonDoc = app.activeDocument;                                                            // Get this document
app.activeDocument = app.documents.getByName(targetDoc);                       // Switch to target document
var scenaristDoc = app.activeDocument;                                                        // Get target document
var scenaristDocTargetLayer = app.activeDocument.activeLayer;                     // Get target active layer
var scenaristDocTargetLayerName = app.activeDocument.activeLayer.name;   // get active layer name
app.activeDocument = buttonDoc;                                                                  // switch back to this document
// Copy it?
if (isGroup == true) {
   if (BOGn.text.length > 0) {
      layerSetBOGRef.duplicate (app.documents.getByName(targetDoc));  // duplicate layer to target document
      app.activeDocument = scenaristDoc;                                                // switch to target document
      var currentLayer = app.activeDocument.activeLayer;                        // get just moved layer
      selLayer(scenaristDocTargetLayerName);                                         // make original active layer active
      // get index of active layer - have to use index to make following move work
      var targetLayers=[];
      targetLayers= getSelectedLayersIdx();
//      makeActiveByIndex( targetLayers[0], false );
      moveLayer(currentLayer.name, targetLayers[0]-1);                          // move it
      selLayer(scenaristDocTargetLayerName);                                         // make original active layer active - for next time
      }
   else if ( !(BOGn.text.length >0)) {
      layerSetBRef.duplicate (app.documents.getByName(targetDoc));       // duplicate layer to target document
      app.activeDocument = scenaristDoc;                                                // switch to target document
      var currentLayer = app.activeDocument.activeLayer;                        // get just moved layer
      selLayer(scenaristDocTargetLayerName);                                         // make original active layer active
      // get index of active layer - have to use index to make following move work
      var targetLayers=[];
      targetLayers= getSelectedLayersIdx();
//      makeActiveByIndex( targetLayers[0], false );
      moveLayer(currentLayer.name, targetLayers[0]-1);                          // move it
      selLayer(scenaristDocTargetLayerName);                                         // make original active layer active - for next time
      }
   app.activeDocument = buttonDoc;                                                   // switch back to this document
   } 
}  //  End of function main

Some notes:

Even though there will only be 1 layer, I used an existing function which works with an array. I didn't want to try and rewrite it.

The makeActiveByIndex call is in the original code (see below). I didn't know why it is there so i put it here and tested with out it. It seems to make no difference.

I had to use the index because the moveLayer code from the listener uses a number. I tried to change that to a name but it didn't like that.

I don't understand why I have to subtract 1 from the index. I alerted it and it comes out completely different numbers than I expected from the order of the layers. The first time around it is 5 but there are only 4 layers.
Also, I first had it in the setup section - above // Copy it?. Then I thought that the duplicate would change things so I moved it to where it is - the number didn't change!

As I said, I would like to have the moved item put at the end of the layer set but I don't recognize a parm in the moveLayer code that is obvious. There is a T which I thought might be it, but changing it to B caused an error. I tried to find what Adjs ment, but could not find it in any of the books I tried.

Here is the code:
Code: Select all// move layer
function moveLayer (moveLayerName, moveToLayerIdx) {
var id263 = charIDToTypeID( "move" );
var desc65 = new ActionDescriptor();
var id264 = charIDToTypeID( "null" );
var ref65 = new ActionReference();
var id265 = charIDToTypeID( "Lyr " );
ref65.putName( id265, moveLayerName );
desc65.putReference( id264, ref65 );
var id266 = charIDToTypeID( "T   " );
var ref66 = new ActionReference();
var id267 = charIDToTypeID( "Lyr " );
ref66.putIndex( id267, moveToLayerIdx );
desc65.putReference( id266, ref66 );
var id268 = charIDToTypeID( "Adjs" );
desc65.putBoolean( id268, false );
executeAction( id263, desc65, DialogModes.NO );
}

I have tested it with multiple runs of the script. It puts the copied layer set under the correct layer. I have added another P: layer in the target and selected it before running the script and the move puts the copied layer at the top of that layer. I have selected a BOG layer and caused the script to create only a B layer set and that is moved to the top of the correct layer set.

The getSelectedLayersIdx(); function I found somwhere (either here or on the Adobe forum) is used earlier in the script to rename the user selected layers and put them in the newly created layer set (BOG/B or just B depending) and that works well. As I mentioned, it 'felt' like something wasn't being refrenced correcty. The 'rename/move layer' works fine and puts the layer at the end of the layer set.

Here is that code:
Code: Select allfor (var a = selLayers.length -1;a>-1;a--) {
   if (Nnum > 0) {
      makeActiveByIndex( selLayers[a], false );
      app.activeDocument.activeLayer.name = 'N'+counter+': '+Bn.text;  // change name
      if (isGroup) {                                                                                  // add to group if there
         app.activeDocument.activeLayer.moveToEnd(layerSetBRef);
         }
      counter = counter +1;
      Nnum = Nnum -1;
      if (Nnum == 0) {
         counter = 0;  // Reset counter for next state, if any
         }
      }
else   if (Snum > 0) {
      makeActiveByIndex( selLayers[a], false );
      app.activeDocument.activeLayer.name = 'S'+counter+': '+Bn.text;  // change name
      if (isGroup) {                                                                                  // add to group if there
         app.activeDocument.activeLayer.moveToEnd(layerSetBRef);
         }
      counter = counter +1;
      Snum = Snum -1;
      if (Snum == 0) {
         counter = 0;  // Reset counter for next state, if any
         }
      }
else   if (Anum > 0) {
      makeActiveByIndex( selLayers[a], false );
      app.activeDocument.activeLayer.name = 'A'+counter+': '+Bn.text;  // change name
      if (isGroup) {                                                                                  // add to group if there
         app.activeDocument.activeLayer.moveToEnd(layerSetBRef);
         }
      counter = counter +1;
      Anum = Anum -1;
      if (Anum == 0) {
         counter = 0;  // Reset counter for next state, if any
         }
      }
   }   

The original had to be modified because the prefix of the name can change and I ran the table 'upside down' so the layers would be in the correct order.

Here are the functions referenced above in case others don't have it:
Code: Select all// Get array of selected layers
function getSelectedLayersIdx(){
var selectedLayers = new Array;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){
   desc = desc.getList( stringIDToTypeID( 'targetLayers' ));
   var c = desc.count
   var selectedLayers = new Array();
   for(var i=0;i<c;i++){
      try{
         activeDocument.backgroundLayer;
         selectedLayers.push(  desc.getReference( i ).getIndex() );
         }
      catch(e){
         selectedLayers.push(  desc.getReference( i ).getIndex()+1 );
         }
      }
      }else{
         var ref = new ActionReference();
         ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" ));
         ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
      try{
         activeDocument.backgroundLayer;
         selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))-1);
         }
      catch(e){
         selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" )));
         }
      }
      return selectedLayers;
};
function makeActiveByIndex( idx, visible ){
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex(charIDToTypeID( "Lyr " ), idx)
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), visible );
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
};
// Check field for numeric
function chkNum(n) {
var numlen = n.length;
for (var i = 0; i !=numlen; i++) {
   aChar = n.substring(i,i+1);
   if (aChar < "0" || aChar > "9")
   return false;
   }
return true;
}
// select a layer
function selLayer (layerName) {
var id44 = charIDToTypeID( "slct" );
var desc13 = new ActionDescriptor();
var id45 = charIDToTypeID( "null" );
var ref12 = new ActionReference();
var id46 = charIDToTypeID( "Lyr " );
ref12.putName( id46, layerName );
desc13.putReference( id45, ref12 );
var id47 = charIDToTypeID( "MkVs" );
desc13.putBoolean( id47, false );
executeAction( id44, desc13, DialogModes.NO );
return;
}

Thanks so much to all who helped. With out the other ideas, I would likely not have thought about trying this one.

Paul Masters