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

paulemasters

Move layer problem

Post by paulemasters »

Hello:

I am new to scripting for PhotoShop and JavaScript. Lurking here and on the Adobe forum I have been able to piece together a script. Thanks to all for their help and code.

Working in CS3.

Everything seems to be working except I can't get a group layer to move under another group layer after it is copied to another document. Here is the relevent code:

// 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 scenaristDocActiveLayer = app.activeDocument.activeLayer; // Get target active layer
var scenaristDocActiveLayerName = 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 in target doc
app.activeDocument = scenaristDoc; // switch to target document
var currentLayer = app.activeDocument.activeLayer; // get just moved layer
app.activeDocument.activeLayer.move( currentLayer, ElementPlacement.PLACEATEND ); // move it
selLayer(scenaristDocActiveLayerName); // set original active layer active - for next time
}
app.activeDocument = buttonDoc; // switch back to this document
}

I may be doing this the hard way but everything works as desired except for the 'move' (underlined).

I want the new group layer to be moved to the 'end' of the group layers (if any) and in the active group layer. I have tried various ElementPlacement.xxx but either I get an error saying there is an illegal parameter (and not saying which one) or the script runs, but the group isn't moved - that is it stays at the top of the layer list where it was copied to.

Thanks for any help.

Paul Masters

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

larsen67

Move layer problem

Post by larsen67 »

I have not tested your script but you look to be moving the 'active layer' and the relative placement is also the 'active layer' that does not make sense… Try using the document as the relative placement object… Something like:

Code: Select allapp.activeDocument.activeLayer.move(app.activeDocument, ElementPlacement.PLACEATEND );

You 'may' need to test that there is no background layer first or this may not be possible…
paulemasters

Move layer problem

Post by paulemasters »

I HATE it when there is a flaw in my logic . I hate it even worse when someone else finds it .

I get easily confused wth all this notation and which goes where. I was a mainframe systems programmer for 30 years and worked with linear languages like COBOL or Assembler. I have worked with procedural languages like SAS. I guess I am too old to grasp this new 'method' .

I tried your suggestion but it put the copied layers after the last one.
Here is, perhaps, a long winded description of what I tried and what happened and what I need.

(Sorry for the leading .s but appearently leading spaces are removed.)

Target document layout:
IG: Menu
..DS Menu Set
....P: Main Menu
Background

The last layer is named Background but does not appear to be 'the' PS background layer. It is not locked.
That document is built with another script. All those layers are Groups with no layers 'inside' them. The P: layer is active when the script completes.

Next the Load Files into Stack... script is run to select and load multiple files.
Those layers are then all selected / made active.
The script in question is run to rename the selected layers and create 2 Groups and put those layers in the last group. Example:

BOG: Extra
..B: Extras
....(renamed layers)

Then that (the top Group) is copied to the target document.
All this seems to work OK.

The last part of the script - what I put in the first post - switches to the target document to get the currently active layer (in this case P:).
That's so it can be set back to active to be ready for the next run of this script.
It is possible that that layer could be a user selected one, so I have no idea what the name may be.

After that the duplicate works.
I switch to the target document to place the just copied group.

If I change the code I sent to:
var currentLayer = app.activeDocument.activeLayer; // get just moved layer
app.activeDocument.activeLayer.move( scenaristDocActiveLayer, ElementPlacement.PLACEAFTER );
selLayer(scenaristDocActiveLayerName); // make original active layer active - for next time

The result is:
IG: Menu
..DS Menu Set
....P: Main Menu
..BOG: Extra
....B: Extras
......(renamed layers)
Background

But the BOG: group should be 'inside' the P: group.

Changing PLACEAFTER to PLACEATEND gives Illegal Argument but doesn't say which one.
INSIDE gives Illegal Argument but doesn't say which one.
PLACEATBEGINNING gives Illegal Argument but doesn't say which one.
PLACEBEFORE works with no errors but results in:

IG: Menu
..DS Menu Set
....BOG: Extra
......B: Extras
........(renamed layers)
....P: Main Menu
Background

Interesting and closer but not what is required.

If this script is run again, the resulting set of layers should follow the last one. Example:

IG: Menu
..DS Menu Set
....P: Main Menu
......BOG: Extra
........B: Extras
..........(renamed layers)
......BOG: Setup
........B: Setup
..........(renamed layers)
......(and so on)
Background

Many iterations of Load Files into Stack... / run this script is likely.

Thanks for your patience and any suggestions.

Paul Masters
Mike Hale

Move layer problem

Post by Mike Hale »

See if this helps. First add the placement argument to the layer duplicate step so it is placed at the top of the layer stack in the target document. Then after you switch document to the target doc make a reference to the group you want to place the copied layer to. Then move the layer.

Code: Select all// setup code here
layerSetBOGRef.duplicate (app.documents.getByName(targetDoc), ElementPlacement.PLACEATBEGINNING); // duplicate layer  to target doc and place at top of layer stack
activeDocument = documents.getByName(targetDoc);
var pGroup = activeDocument.layers.getByName('P: Main Menu');// or whatever the layerset name is
activeDocument.activeLayer.move (pGroup , ElementPlacement.INSIDE);// move the just copied layer into the target group
// follow-up code
paulemasters

Move layer problem

Post by paulemasters »

Thanks for the reply.

I put your code in the script.
All works fine until the var pGroup which gets error 'No such element'.
I copy/paste the layer properties name and got the same error.
When the script stops, the active document appears to be correct, that is the one with that layer.

FWIW... even before your addition to the duplicate command, the items copied appear at the top of the layer list and the first layer is selected.

Your pGroup should be the same as my scenaristDocActiveLayer, or at least I would think.

Wondering if the duplicate changed the location of things, although with getting by name, that shouldn't matter. I changed your code as follows:

Code: Select alllayerSetBOGRef.duplicate (app.documents.getByName(targetDoc), ElementPlacement.PLACEATEND); // duplicate layer  to target doc and place at top of layer stack
activeDocument = documents.getByName(targetDoc);
var pGroup = activeDocument.layers.getByName('P: Main Menu');// or whatever the layerset name is
activeDocument.activeLayer.move (scenaristDocActiveLayer , ElementPlacement.INSIDE);// move the just copied layer into the target group

The duplicated items are at the bottom (after the last layer) this time.
I got the Illegal argument on the move. So, I guess pGroup and scenaristDocActiveLayer aren't the same, but the commands to get them are, sort of, I get the layer that is active and you get the layer by name.

Trying to be logical, which I realize doesn't always work , I tried to do the duplicate from the targetDoc side as follows:

Code: Select all      app.activeDocument = scenaristDoc;                                                // switch to target document
      app.activeDocument.activeLayer.moveToEnd(buttonDoc.layerSetBOGRef);

But that got "Illegal argument - argument 1 Required value missing".
If I remove the buttonDoc. I get "Illegal argument".

Thanks for any suggestions.

Paul Masters
Mike Hale

Move layer problem

Post by Mike Hale »

If you are getting a 'No such element' error when trying to reference a layer by name it means there is no layer at that level with that name. You may have to edit the layer name. Or if pGroup is not at the top level you will have to change activeDocument.layers to whatever the group that contains pGroup.
paulemasters

Move layer problem

Post by paulemasters »

Thanks for the quick reply.

Now I am really confused (even more so than before).

The Group does exist. I copied it's name to the command but it gave the same error???

That group is under a group that is under a group. So I need to have active the group above the desired group? But that is also inside a group. (See target document layout in a previous post.)

This format is required by a product that will process the completed PSD. It is a menu for BD authoring.
Also, it is possible to have additional P: groups under the DS: group
P = Page and there may be more than one.
BOG contains B (buttons) and there will be more than one - BOGs are contined in the P(age) group.

The product processing the PSD reads the layers from top to bottom. It would be nice if the added 'sets' be put top to bottom in the group. If not, I can write the instructions to have the user create them 'upside down' if necessary.

As I have no control over having multiple pages (likely) or multiple buttons in a BOG (rare but can happen - which would mean that the BOG group would be active not the P group). I have no idea what the name is / will be or which group the user will select indicating where that the next 'set' is to be placed.

This may be compilcated for a script, but having it will save people a lot of time apposed to doing all this manually.

Since my last post I have tried some other varations but all give errors.

Thanks to all for your patience and help.

Paul Masters
Mike Hale

Move layer problem

Post by Mike Hale »

The way the DOM works is every level in the layer's panel has it's own layers, artLayers, and layerSets collection. That often makes it hard to work with layers with a script. One thing I find that helps if all your layers have unique names is to use scriptlistener to find the layer and make it active no matter where it is in the layer stack.

Code: Select allfunction makeActiveByName( lyrName ){
   try{
      var desc = new ActionDescriptor();
         var ref = new ActionReference();
         ref.putName( charIDToTypeID( "Lyr " ), lyrName );
      desc.putReference( charIDToTypeID( "null" ), ref );
      desc.putBoolean( charIDToTypeID( "MkVs" ), false );
      executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
      return activeDocument.activeLayer;
   }catch(e){}
}

You didn't post all your code and I don't have a sample document with that layer stack but this should be close( again if I understand what you are trying to do ). Note if requires the function above and the other code from your script that you did not post. You may need to edit some names, etc.
Code: Select all// Get documents - get target active layer
var buttonDoc = app.activeDocument; // Get this document
var scenaristDoc = app.documents.getByName('targetDoc'); //  make a refence to the target doc
var scenaristDocActiveLayer = scenaristDoc.activeLayer; // Get target active layer
var scenaristDocActiveLayerName = scenaristDoc.activeLayer.name; // get active layer name
// Copy it?
if (isGroup == true) {
if (BOGn.text.length > 0) {
layerSetBOGRef.duplicate (app.documents.getByName(targetDoc), ElementPlacement.PLACEATBEGINNING); // duplicate layer  to target doc and place at top of layer stack
app.activeDocument = scenaristDoc; // switch to target document
var currentLayer = scenaristDoc.activeLayer; // get just moved layer
var targetGroup = makeActiveByName('P: Main Menu');// or whatever the layerSet you want to place the duped layer is named
currentLayer.move(  targetGroup, ElementPlacement.INSIDE ); // move it
selLayer(scenaristDocActiveLayerName); // set original active layer active - for next time
}
app.activeDocument = buttonDoc; // switch back to this document
}
paulemasters

Move layer problem

Post by paulemasters »

Thanks for your time.

var scenaristDoc = app.documents.getByName('targetDoc'); // make a refence to the target doc
Failed with No such element. targetDoc is a variable. I removed the quotes.

currentLayer.move( targetGroup, ElementPlacement.INSIDE ); // move it
Failed with Illegal argument. I've gotten a number of those .
It's unfortunate that it doesn't say which argument as there are two: targetGroup and INSIDE.
As mentioned in an earlier post, with a different command, I tried all the possible ElementPlacements and mostly got an Illegal argument. The reference says that all are not valid in all cases, but it doesn't elabarate.

It 'feels' like that the layer being moved to has to be referenced as a layer set. But I have yet to find a way to do that. I would think that var something = ...activeLayer would pick up / reference all the attributes of the active layer, but it appears not to be doing so.

The complete script is long. Everything works up to this point. The code origianlly sent is the very last before the end of the main function. Everything in that works except for the correct placement of the duplicated layers. The if (isGroup == true) says that either the BOG or B layer sets were created, if not no move is done. The BOGn.text.length > 0) says to move that layer set. There is an else if for the B layer set that follows to move that layer set (left out to make things simpler - if one works the other should be the same except for the duplicated layer). (BOG always has a B, but a B can be created with out a BOG).

Thanks for all your trouble.

Paul Masters
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.