Monday, December 17, 2018

#1 2018-10-05 12:22:34 pm

Jono
Member
Registered: 2008-07-08
Posts: 95

Help with part of a Photoshop script?

I cobbled together quite a large script for Photoshop, but have run into a problem with part of it. Part of the script moves the selected layer in Photoshop to a specified folder/group. The part I'm having difficulty with is if the selected layer is within a folder, or a few nested folders.

If I know how many folders the selected layer is in (and their names) then I can adjust the script accordingly, but I'd like it to work when nested in any amount of folders so I don't have to keep changing the script


Here's the part of the script:

Applescript:

tell application id "com.adobe.Photoshop"
   tell current document
       set selectedLayer to name of current layer
       set layerContainer to name of container of current layer
       set rootContainer to name of container of container of current layer

       
       move layer selectedLayer of layer set layerContainer of layer set rootContainer to layer set "mask" of layer set "colour fill" of layer set "Artwork"
   end tell
end tell

So the part at the bottom is fine where it moves the selected layer to 'Artwork' folder > 'colour fill' folder > 'mask' folder.

I guess I'd just need a script to count the number of folders the selected layer is in (and set each nested folder as variables?) so that I could move the selected layer no matter how many folders it's nested in (it seems you have to specify the folders that the selected layer is nested in, in order to be able to move the layer to another folder).

Offline

 

#2 2018-10-05 07:39:13 pm

t.spoon
Member
From:: BFE, Massachusetts
Registered: 2013-01-13
Posts: 368

Re: Help with part of a Photoshop script?

I'd bypass all the "figuring out how deep the nesting goes" thing by getting the Photoshop Index Number for the selected layer, convert the index to a reference, then move it by reference.

I recently posted this script
https://macscripter.net/viewtopic.php?id=46407
Which does that, except it's for renaming layers instead of moving layers.

So it would just need a minor modification, as below.

As it stands now, it would move any set of selected layers to the destination - you could do more than one at a time if you wanted.

Applescript:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

global foundLayer -- recursive function to drill down arbitrary layer nesting, setting global to exit function regardless of how deep the calls go
set selectedLayerIndexes to get_selected_layer_indexes() -- get the index numbers for all selected layers
set selectedLayerReferences to {}
tell application "Adobe Photoshop CC 2018" to tell the current document to set allLayers to the layers

-- convert each layer index to a layer reference
repeat with aLayerIndex in selectedLayerIndexes
   set foundLayer to false
   copy recurse_layer_sets(allLayers, aLayerIndex) to end of selectedLayerReferences
end repeat

-- move each layer
tell application "Adobe Photoshop CC 2018"
   set currentDoc to the current document
   tell currentDoc
       set repeatCount to 0
       repeat with i from (count of selectedLayerReferences) to 1 by -1
           set aLayer to item i of selectedLayerReferences
           move aLayer to layer set "mask" of layer set "colour fill" of layer set "Artwork"
       end repeat
   end tell
end tell

-- drills through all layer sets to look up layers by itemindex and return an Applescript reference to the layer
on recurse_layer_sets(layerList, theItemIndex)
   set theItemIndex to theItemIndex as number -- it's already an integer; not sure why this is necessary
   if foundLayer is not false then return foundLayer
   tell application "Adobe Photoshop CC 2018"
       set currentDoc to the current document
       tell currentDoc
           set layerGroupCount to the count of layerList
           repeat with i from 1 to layerGroupCount
               set aLayer to item i of layerList
               if the (itemindex of aLayer) as number is theItemIndex then
                   set foundLayer to aLayer
                   exit repeat
               else
                   if the class of aLayer is layer set then my recurse_layer_sets((layers of aLayer), theItemIndex)
               end if
           end repeat
       end tell
   end tell
   return foundLayer
end recurse_layer_sets

-- AM code to get the indexes of all selected layers
on get_selected_layer_indexes()
   tell application "Adobe Photoshop CC 2018"
       set selectedLayers to do javascript "
getSelectedLayersIdx()
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 {
docRef.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 {
docRef.backgroundLayer;
selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID(\"ItmI\")) - 1);
} catch (e) {
selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID(\"ItmI\")));
}
}
return selectedLayers;
} "

   end tell
   set selectedLayersListText to text_to_list(selectedLayers, ",") -- Javascript spits out comma delimited list
   -- Javascript also spits out numbers as strings; switch to integers
   set selectedLayersList to {}
   repeat with anItem in selectedLayersListText
       set selectedLayersList to selectedLayersList & (anItem as number)
   end repeat
   return selectedLayersList
end get_selected_layer_indexes

-- converts text delimited strings to AS lists
on text_to_list(someText, aSeparator)
   set {delimitHolder, AppleScript's text item delimiters} to {AppleScript's text item delimiters, aSeparator}
   set outputList to the text items of someText
   set AppleScript's text item delimiters to delimitHolder
   return outputList
end text_to_list


Hackintosh built February, 2012 |  Mac OS Sierra
GIGABYTE GA-Z68X-UD3H-B3 | Core i5 2500k | 16 GB DDR3 | GIGABYTE Geforce 1050 TI 4GB
250 GB Samsung 850 EVO | 4 TB RAID
Dell Ultrasharp U3011 | Dell Ultrasharp 2007FPb

Offline

 

#3 2018-10-07 03:01:52 am

Jono
Member
Registered: 2008-07-08
Posts: 95

Re: Help with part of a Photoshop script?

That's great, thanks a lot!

If I select a single layer it works perfectly. But if I select multiple layers then it doesn't quite work right, it moves some of the layers but not all of them and shows an error.

For example, here I select 4 layers

screenshot_1


Then run script and one of the selected layers doesn't get moved (green), and a layer that wasn't selected gets moved (orange).

screenshot_2


When running the script it highlights this line

Applescript:

move aLayer to layer set "mask" of layer set "colour fill" of layer set "Artwork"

And the error message in Script Editor says:

error "Adobe Photoshop CC 2018 got an error: Can’t get art layer 4 of layer set 2 of layer set 1 of document \"Test_Document.psd\"." number -1728 from art layer 4 of layer set 2 of layer set 1 of document "Test_Document.psd"


Any idea on what could be the problem there?

Offline

 

#4 2018-10-07 08:43:13 am

Marc Anthony
Member
From:: Dallas, TX
Registered: 2006-04-27
Posts: 843

Re: Help with part of a Photoshop script?

Hi. If I understand the original question, the problem appears to be that the selection is being purposefully deconstructed and reconstructed when the object reference is fine as-is.

Applescript:

tell application "Adobe Photoshop CS3"'s document 1 to move current layer to layer set "mask" of layer set "colour fill" of layer set "Artwork"

Offline

 

#5 2018-10-07 12:29:15 pm

t.spoon
Member
From:: BFE, Massachusetts
Registered: 2013-01-13
Posts: 368

Re: Help with part of a Photoshop script?

Ah, yes, I see the problem here. The AppleScript references are not absolute references to the layers - they are relative references. Once you start moving things, an Applescript reference like:

art layer 4 of layer set 2 of layer set 1 of document \"Test_Document.psd\"



won't still refer to the same layer if other layers have moved around.

So it'll always move a single selected layer correctly, but after that, all bets are off because that first move starts changing what (if anything) the remaining references refer to.

I haven't experimented yet, but I don't think Marc's solution is going to solve this situation with multiple layers, because Applescript's "current layer" only refers to the active layer, not the other selected layers when there is a multiple-layer selection.

This is certainly fixable. But I need to check and see what layer identifier remains static as the layers are moved, and use that to identify them to perform the move.

I don't have time for that at the moment, but maybe in the next few days.


Hackintosh built February, 2012 |  Mac OS Sierra
GIGABYTE GA-Z68X-UD3H-B3 | Core i5 2500k | 16 GB DDR3 | GIGABYTE Geforce 1050 TI 4GB
250 GB Samsung 850 EVO | 4 TB RAID
Dell Ultrasharp U3011 | Dell Ultrasharp 2007FPb

Offline

 

#6 2018-10-07 01:31:36 pm

Jono
Member
Registered: 2008-07-08
Posts: 95

Re: Help with part of a Photoshop script?

Marc Anthony wrote:

Hi. If I understand the original question, the problem appears to be that the selection is being purposefully deconstructed and reconstructed when the object reference is fine as-is.

Applescript:

tell application "Adobe Photoshop CS3"'s document 1 to move current layer to layer set "mask" of layer set "colour fill" of layer set "Artwork"


I'm posting my whole script below so you can see what's going on. The script creates the Artwork, colour fill, and mask folders, and in the process loses focus of the selected layer. So in my existing script it has to specify the path to the previously selected layer in order to move it.

But if there's a better/simpler way then please let me know smile


t.spoon wrote:

Ah, yes, I see the problem here.
This is certainly fixable. But I need to check and see what layer identifier remains static as the layers are moved, and use that to identify them to perform the move.

I don't have time for that at the moment, but maybe in the next few days.


Sure, no hurry. I appreciate the help, so whenever's good for you big_smile


Here's the whole of my script:

Applescript:

set colourFromClipboard to (get the clipboard)


tell application id "com.adobe.Photoshop"
   activate
   tell current document
       set selectedLayer to current layer
       set layerName to name of current layer
       set layerContainer to name of container of current layer
       
       (* Make sure current layer/group as visible *)
       set visible of selectedLayer to true
   end tell
   
   
   (* Fill selected vector shape with black *)
   tell current document
       do javascript "var c = new SolidColor();
c.rgb.hexValue = '000000'

set_fill_color(c);
//set_stroke_color(c);
function set_stroke_color(c)
{
try {
var d = new ActionDescriptor();
var r = new ActionReference();
r.putEnumerated(stringIDToTypeID('contentLayer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
d.putReference(stringIDToTypeID('null'), r);
var d1 = new ActionDescriptor();
var d2 = new ActionDescriptor();
var d3 = new ActionDescriptor();
var d4 = new ActionDescriptor();
d4.putDouble(stringIDToTypeID('red'), c.rgb.red);
d4.putDouble(stringIDToTypeID('green'), c.rgb.green);
d4.putDouble(stringIDToTypeID('blue'), c.rgb.blue);
d3.putObject(stringIDToTypeID('color'), stringIDToTypeID('RGBColor'), d4);
d2.putObject(stringIDToTypeID('strokeStyleContent'), stringIDToTypeID('solidColorLayer'), d3);
d2.putBoolean(stringIDToTypeID('strokeEnabled'), true);
d1.putObject(stringIDToTypeID('strokeStyle'), stringIDToTypeID('strokeStyle'), d2);
d.putObject(stringIDToTypeID('to'), stringIDToTypeID('shapeStyle'), d1);
executeAction(stringIDToTypeID('set'), d, DialogModes.NO);
}
catch (e) { throw(e); }
}
function set_fill_color(c)
{
try {
var d = new ActionDescriptor();
var r = new ActionReference();
r.putEnumerated(stringIDToTypeID('contentLayer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
d.putReference(stringIDToTypeID('null'), r);
var d1 = new ActionDescriptor();
var d2 = new ActionDescriptor();
var d3 = new ActionDescriptor();
d3.putDouble(stringIDToTypeID('red'), c.rgb.red);
d3.putDouble(stringIDToTypeID('green'), c.rgb.green);
d3.putDouble(stringIDToTypeID('blue'), c.rgb.blue);
d2.putObject(stringIDToTypeID('color'), stringIDToTypeID('RGBColor'), d3);
d1.putObject(stringIDToTypeID('fillContents'), stringIDToTypeID('solidColorLayer'), d2);
var d4 = new ActionDescriptor();
d4.putBoolean(stringIDToTypeID('fillEnabled'), true);
d1.putObject(stringIDToTypeID('strokeStyle'), stringIDToTypeID('strokeStyle'), d4);
d.putObject(stringIDToTypeID('to'), stringIDToTypeID('shapeStyle'), d1);
executeAction(stringIDToTypeID('set'), d, DialogModes.NO);
}
catch (e) { throw(e); }
}"
show debugger on runtime error
   end tell
   
   
   (* Create Folders *)
   tell current document
       set artworkFolder to "Artwork"
       if exists layer set named artworkFolder then
           (* Do nothing *)
       else
           make new layer set at beginning with properties {name:artworkFolder}
       end if
       
       set colourFillFolder to "colour fill"
       if exists layer set named colourFillFolder in layer set artworkFolder then
           (* Do nothing *)
       else
           make new layer set in layer set artworkFolder with properties {name:colourFillFolder}
       end if
       
       set blendingMaskFolder to "mask"
       if exists layer set named blendingMaskFolder in layer set colourFillFolder in layer set artworkFolder then
           (* Do nothing *)
       else
           make new layer set in layer set colourFillFolder in layer set artworkFolder ¬
               with properties {name:blendingMaskFolder}
       end if
   end tell
   
   
   (* Set blending mode for mask folder *)
   tell current document
       do javascript "
blend_if(0,0, 255,255, 0,0, 0,255, 'k');
function blend_if(db0,db1, dw0,dw1, sb0,sb1, sw0,sw1, ch)
{
try {
if (db0 == undefined) db0 = 0;
if (db1 == undefined) db1 = db0;
if (dw0 == undefined) dw0 = 255;
if (dw1 == undefined) dw1 = dw0;
if (sb0 == undefined) sb0 = 0;
if (sb1 == undefined) sb1 = sb0;
if (sw0 == undefined) sw0 = 255;
if (sw1 == undefined) sw1 = sw0;
if (ch == undefined) ch = 'krgb';
var use_r = false;
var use_g = false;
var use_b = false;
var use_k = false;
if (ch.indexOf('r') >= 0) use_r = true;
if (ch.indexOf('g') >= 0) use_g = true;
if (ch.indexOf('b') >= 0) use_b = true;
if (ch.indexOf('k') >= 0) use_k = true;
var desc3 = new ActionDescriptor();
var desc4 = new ActionDescriptor();
var ref1 = new ActionReference();
var list1 = new ActionList();
ref1.putEnumerated( charIDToTypeID( 'Lyr ' ), charIDToTypeID( 'Ordn' ), charIDToTypeID( 'Trgt' ) );
desc3.putReference( charIDToTypeID( 'null' ), ref1 );
for (var i = 0; i < 4; i++)
{
var desc5 = new ActionDescriptor();
var ref2 = new ActionReference();
use_cont = false;
switch ( i )
{
case 0: if (!use_k) { use_cont = true; break; } ref2.putEnumerated( charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Gry ' ) ); break;
case 1: if (!use_r) { use_cont = true; break; } ref2.putEnumerated( charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Rd ' ) ); break;
case 2: if (!use_g) { use_cont = true; break; } ref2.putEnumerated( charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Grn ' ) ); break;
case 3: if (!use_b) { use_cont = true; break; } ref2.putEnumerated( charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Chnl' ), charIDToTypeID( 'Bl ' ) ); break;
}
if (use_cont) continue;
desc5.putReference( charIDToTypeID( 'Chnl' ), ref2 );
desc5.putInteger( charIDToTypeID( 'SrcB' ), sb0 );
desc5.putInteger( charIDToTypeID( 'Srcl' ), sb1 );
desc5.putInteger( charIDToTypeID( 'SrcW' ), sw0 );
desc5.putInteger( charIDToTypeID( 'Srcm' ), sw1 );
desc5.putInteger( charIDToTypeID( 'DstB' ), db0 );
desc5.putInteger( charIDToTypeID( 'Dstl' ), db1 );
desc5.putInteger( charIDToTypeID( 'DstW' ), dw0 );
desc5.putInteger( charIDToTypeID( 'Dstt' ), dw1 );
list1.putObject( charIDToTypeID( 'Blnd' ), desc5 );
}
desc4.putList( charIDToTypeID( 'Blnd' ), list1 );
desc3.putObject( charIDToTypeID( 'T ' ), charIDToTypeID( 'Lyr ' ), desc4 );
executeAction( charIDToTypeID( 'setd' ), desc3, DialogModes.NO );
}
catch (e) { alert(e); }
}"
show debugger on runtime error
   end tell
   
   
   (* Move selected layer to 'mask' folder *)
   tell current document
       move layer layerName of layer set layerContainer to layer set blendingMaskFolder of layer set colourFillFolder of layer set artworkFolder
       (* Select 'colour fill' folder *)
       set current layer to layer set colourFillFolder of layer set artworkFolder
   end tell
end tell


(* Show dialog & ask to choose colour *)
activate me
set colourList to {"Clipboard (#" & colourFromClipboard & ")", "Black", "White"}
set chosenColour to (choose from list colourList with prompt "Fill Colour?" without multiple selections allowed) as text

if chosenColour is "Clipboard (#" & colourFromClipboard & ")" then
   set theColour to colourFromClipboard
   
else if chosenColour is "Black" then
   set theColour to "000000"
   
else if chosenColour is "White" then
   set theColour to "FFFFFF"
end if


(* Add chosen colour to folder as colour overlay style *)
tell application id "com.adobe.Photoshop"
   tell current document
       do javascript "var c = new SolidColor();
c.rgb.hexValue = "
& quoted form of theColour & "

app.activeDocument.suspendHistory('TMP', 'aaa()');
executeAction( charIDToTypeID( 'undo' ), undefined, DialogModes.NO );
executeAction( charIDToTypeID( 'PaFX' ), undefined, DialogModes.NO );
function aaa()
{
app.activeDocument.artLayers.add();
var idsetd = charIDToTypeID( 'setd' );
var desc9 = new ActionDescriptor();
var idnull = charIDToTypeID( 'null' );
var ref1 = new ActionReference();
var idPrpr = charIDToTypeID( 'Prpr' );
var idLefx = charIDToTypeID( 'Lefx' );
ref1.putProperty( idPrpr, idLefx );
var idLyr = charIDToTypeID( 'Lyr ' );
var idOrdn = charIDToTypeID( 'Ordn' );
var idTrgt = charIDToTypeID( 'Trgt' );
ref1.putEnumerated( idLyr, idOrdn, idTrgt );
desc9.putReference( idnull, ref1 );
var idT = charIDToTypeID( 'T ' );
var desc10 = new ActionDescriptor();
var idScl = charIDToTypeID( 'Scl ' );
var idPrc = charIDToTypeID( '#Prc' );
desc10.putUnitDouble( idScl, idPrc, 100.000000 );
var idSoFi = charIDToTypeID( 'SoFi' );
var desc11 = new ActionDescriptor();
var idenab = charIDToTypeID( 'enab' );
desc11.putBoolean( idenab, true );
var idpresent = stringIDToTypeID( 'present' );
desc11.putBoolean( idpresent, true );
var idshowInDialog = stringIDToTypeID( 'showInDialog' );
desc11.putBoolean( idshowInDialog, true );
var idMd = charIDToTypeID( 'Md ' );
var idBlnM = charIDToTypeID( 'BlnM' );
var idNrml = charIDToTypeID( 'Nrml' );
desc11.putEnumerated( idMd, idBlnM, idNrml );
var idClr = charIDToTypeID( 'Clr ' );
var desc12 = new ActionDescriptor();
var idRd = charIDToTypeID( 'Rd ' );
desc12.putDouble( idRd, c.rgb.red ); // RED
var idGrn = charIDToTypeID( 'Grn ' );
desc12.putDouble( idGrn, c.rgb.green ); // GREEN
var idBl = charIDToTypeID( 'Bl ' );
desc12.putDouble( idBl, c.rgb.blue ); // BLUE
var idRGBC = charIDToTypeID( 'RGBC' );
desc11.putObject( idClr, idRGBC, desc12 );
var idOpct = charIDToTypeID( 'Opct' );
var idPrc = charIDToTypeID( '#Prc' );
desc11.putUnitDouble( idOpct, idPrc, 100.000000 );
var idSoFi = charIDToTypeID( 'SoFi' );
desc10.putObject( idSoFi, idSoFi, desc11 );
var idLefx = charIDToTypeID( 'Lefx' );
desc9.putObject( idT, idLefx, desc10 );
executeAction( idsetd, desc9, DialogModes.NO );
executeAction( charIDToTypeID( 'CpFX' ), undefined, DialogModes.NO );
}"
show debugger on runtime error
   end tell
end tell


(* Select previously selected layer *)
tell application id "com.adobe.Photoshop"
   activate
   tell current document
       set current layer to layer layerName of layer set blendingMaskFolder ¬
           of layer set colourFillFolder of layer set artworkFolder
   end tell
end tell

Last edited by Jono (2018-10-07 01:37:46 pm)

Offline

 

#7 2018-10-08 06:12:46 pm

Marc Anthony
Member
From:: Dallas, TX
Registered: 2006-04-27
Posts: 843

Re: Help with part of a Photoshop script?

Current layer is problematic, as there can be only one and the references are relative, as noted by t.spoon. The best option may be to abandon your desired multi-selection method, which become even more troublesome with nested items. Your best alternative to that option may be to move the selecting into the script, excepting the first instance.



Applescript:

tell application "Adobe Photoshop CS3"'s document 1
   set isTarget to current layer
   if exists layer set "art"'s layer set "fill"'s layer set "mask" then
       set nextTarget to layer set "art"'s layer set "fill"'s layer set "mask"
   else
       set nextTarget to make layer set with properties {name:"mask"} at make layer set with properties {name:"fill"} at make layer set with properties {name:"art"}
   end if
   if isTarget's container's class = document then
       try --prevent action on immovable objects
           repeat with focus in my (choose from list (get art layers's name) with multiple selections allowed)
               move layer (focus's contents) to nextTarget
           end repeat
       end try
   else
       try --ditto
           repeat with focus in my (choose from list (get isTarget's container's art layers's name) with multiple selections allowed)
               move current layer's container's layer (focus's contents) to nextTarget
           end repeat
       end try
   end if
end tell

Offline

 

#8 2018-10-09 04:22:54 am

Jono
Member
Registered: 2008-07-08
Posts: 95

Re: Help with part of a Photoshop script?

Being able to select multiple layers and have them moved would be good, but not essential smile

I tried your script, but unfortunately thew up an error:

Applescript:

error "Can’t get container of current layer." number -1728 from «class ctnr» of «class crLr»

Offline

 

#9 2018-10-09 06:40:43 am

Marc Anthony
Member
From:: Dallas, TX
Registered: 2006-04-27
Posts: 843

Re: Help with part of a Photoshop script?

What are you initially selecting? It's fine to select a layer within a layer set, but I haven't accounted for the eventuality that the initial item actually is a layer set. Try a couple different choices and post more detail if it continues to fail.

Offline

 

#10 2018-10-09 02:26:44 pm

t.spoon
Member
From:: BFE, Massachusetts
Registered: 2013-01-13
Posts: 368

Re: Help with part of a Photoshop script?

I'm sure this could be much, much simpler if I knew more Javascript AM code.

But in some testing I did, it seems to be working.

Photoshop's "layer index" that the javascript function returns is the same as the Applescript references in that it's relative - move one layer, and the rest of the references change what they refer to.

There's "layer ID," which stays static with moves.

I couldn't find code to return the layer ID's though.

So I'm still getting the indexes of the selected layers, then converting them to a list of Layer ID's. Then I one by one convert the layer ID's to references and move them. Let me know if this works for you.

Applescript:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

tell application "Adobe Photoshop CC 2018"
   tell the current document
       set allLayers to the layers
       set moveToLayerSet to layer set "Move To Folder" -- set the location you want the files moved to here
   end tell
end tell

global foundLayerID -- recursive function to drill down arbitrary layer nesting, setting global to exit function regardless of how deep the calls go
global foundLayerReference
set selectedLayerIndexes to get_selected_layer_indexes() -- get the index numbers for all selected layers
set selectedLayerIDs to {}

-- convert each layer index to a layer reference
repeat with aLayerIndex in selectedLayerIndexes
   set foundLayerID to false
   copy get_layer_ID_from_layer_index(allLayers, aLayerIndex) to end of selectedLayerIDs
end repeat

move_layers_by_layer_ID(moveToLayerSet, allLayers, selectedLayerIDs)

on move_layers_by_layer_ID(moveLocation, layerList, moveLayerIDs)
   set moveLayerCount to the count of moveLayerIDs
   repeat with i from 1 to moveLayerCount
       set aLayerID to item i of moveLayerIDs
       set foundLayerReference to false
       set layerRef to my get_layer_reference_from_layerID(layerList, aLayerID)
       tell application "Adobe Photoshop CC 2018" to tell the current document to move layerRef to moveLocation
   end repeat
   
end move_layers_by_layer_ID

on get_layer_reference_from_layerID(layerList, layerID)
   set layerID to layerID as number
   if foundLayerReference is not false then return foundLayerReference
   tell application "Adobe Photoshop CC 2018"
       tell the current document
           set layerGroupCount to the count of layerList
           repeat with i from 1 to layerGroupCount
               set aLayer to item i of layerList
               if the (id of aLayer) as number is layerID then
                   set foundLayerReference to aLayer
                   exit repeat
               else
                   if the class of aLayer is layer set then my get_layer_reference_from_layerID((layers of aLayer), layerID)
               end if
           end repeat
       end tell
   end tell
   return foundLayerReference
end get_layer_reference_from_layerID


on get_layer_ID_from_layer_index(layerList, theItemIndex)
   set theItemIndex to theItemIndex as number -- it's already an integer; not sure why this is necessary
   if foundLayerID is not false then return foundLayerID
   tell application "Adobe Photoshop CC 2018"
       tell the current document
           set layerGroupCount to the count of layerList
           repeat with i from 1 to layerGroupCount
               set aLayer to item i of layerList
               if the (itemindex of aLayer) as number is theItemIndex then
                   set foundLayerID to the id of aLayer
                   exit repeat
               else
                   if the class of aLayer is layer set then my get_layer_ID_from_layer_index((layers of aLayer), theItemIndex)
               end if
           end repeat
       end tell
   end tell
   return foundLayerID
end get_layer_ID_from_layer_index

-- AM code to get the indexes of all selected layers
on get_selected_layer_indexes()
   tell application "Adobe Photoshop CC 2018"
       set selectedLayers to do javascript "
getSelectedLayersIdx()
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 {
docRef.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 {
docRef.backgroundLayer;
selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID(\"ItmI\")) - 1);
} catch (e) {
selectedLayers.push(executeActionGet(ref).getInteger(charIDToTypeID(\"ItmI\")));
}
}
return selectedLayers;
} "

   end tell
   set selectedLayersListText to text_to_list(selectedLayers, ",") -- Javascript spits out comma delimited list
   -- Javascript also spits out numbers as strings; switch to integers
   set selectedLayersList to {}
   repeat with anItem in selectedLayersListText
       set selectedLayersList to selectedLayersList & (anItem as number)
   end repeat
   return selectedLayersList
end get_selected_layer_indexes

-- converts text delimited strings to AS lists
on text_to_list(someText, aSeparator)
   set {delimitHolder, AppleScript's text item delimiters} to {AppleScript's text item delimiters, aSeparator}
   set outputList to the text items of someText
   set AppleScript's text item delimiters to delimitHolder
   return outputList
end text_to_list

Last edited by t.spoon (2018-10-09 02:28:37 pm)


Hackintosh built February, 2012 |  Mac OS Sierra
GIGABYTE GA-Z68X-UD3H-B3 | Core i5 2500k | 16 GB DDR3 | GIGABYTE Geforce 1050 TI 4GB
250 GB Samsung 850 EVO | 4 TB RAID
Dell Ultrasharp U3011 | Dell Ultrasharp 2007FPb

Offline

 

#11 2018-10-09 03:39:22 pm

Jono
Member
Registered: 2008-07-08
Posts: 95

Re: Help with part of a Photoshop script?

Marc Anthony wrote:

What are you initially selecting? It's fine to select a layer within a layer set, but I haven't accounted for the eventuality that the initial item actually is a layer set. Try a couple different choices and post more detail if it continues to fail.


I just tried selecting 'regular' single layers.

One inside a single folder, and one not in a folder. When it shows the error message in Script Editor it also highlights 'document' in this line of the script:

Applescript:

if isTarget's «class ctnr»'s class = document then

Offline

 

#12 2018-10-09 03:44:43 pm

Jono
Member
Registered: 2008-07-08
Posts: 95

Re: Help with part of a Photoshop script?

t.spoon wrote:

I'm sure this could be much, much simpler if I knew more Javascript AM code.

But in some testing I did, it seems to be working.

Photoshop's "layer index" that the javascript function returns is the same as the Applescript references in that it's relative - move one layer, and the rest of the references change what they refer to.

There's "layer ID," which stays static with moves.

I couldn't find code to return the layer ID's though.

So I'm still getting the indexes of the selected layers, then converting them to a list of Layer ID's. Then I one by one convert the layer ID's to references and move them. Let me know if this works for you.


Yeah, you would have thought it would be much more straightforward than this!

But this works perfectly (with multiple layers selected), thank you so much for the help! big_smile

Offline

 

#13 2018-10-09 07:09:24 pm

Marc Anthony
Member
From:: Dallas, TX
Registered: 2006-04-27
Posts: 843

Re: Help with part of a Photoshop script?

Hmm. t.spoon's code appears to not be backwards compatible, as it states a requested property is unavailable, and I don't understand enough JavaScript to attempt to modify the method for my use.

I suspect that you edited my code to reflect the application ID as the tell object, as in your other posts; my dictionary loses the connection when telling "com.adobe..." and returns the same raw events and subsequent error you reported.  For my reference, if you restart PS and plug in your literal version into the code in post #7, does it work? If it still errors, please post the event log from this:

Applescript:


tell application "Adobe Photoshop CS3" --change to your version... Adobe Photoshop CC?
   activate (launch)
   tell (make document) to {its class, current layer's class, current layer's container, current layer's container's class}
end tell

Offline

 

#14 2018-10-10 05:33:39 am

Jono
Member
Registered: 2008-07-08
Posts: 95

Re: Help with part of a Photoshop script?

Thanks for persevering with this smile

I tried your original script again, but only changed 'tell application "Adobe Photoshop CS3"' to 'tell application "Adobe Photoshop CC 2018'.

After playing around with it I have managed to get it to work… sort of.

When I run it for the first time I get the same error as always (but can see that the 'art', 'fill' and 'mask' folders were successfully created). If I select the layer I want to move again, and then run the script again (after the folders have been created when the script ran for the first time) then it works fine.

Could it be that after the script has run the part that creates the folders (and the 'mask' folder is selected in the layers list in Ps) it loses focus/reference to the original selected layer?
And so it works the second time around because focus is on the selected layer, and it doesn't need to create the folders again?


Here's the result of the last script you posted:

Applescript:

tell application "Adobe Photoshop CC 2018"
   launch
   activate
   make new document
       --> document "Untitled-1"
   get class of document "Untitled-1"
       --> document
   get class of current layer of document "Untitled-1"
       --> art layer
   get container of current layer of document "Untitled-1"
       --> document "Untitled-1"
   get class of container of current layer of document "Untitled-1"
       --> document
end tell
Result:
{document, art layer, document "Untitled-1" of application "Adobe Photoshop CC 2018", document}

Offline

 

#15 2018-10-15 12:21:29 am

Jono
Member
Registered: 2008-07-08
Posts: 95

Re: Help with part of a Photoshop script?

t.spoon wrote:


So I'm still getting the indexes of the selected layers, then converting them to a list of Layer ID's. Then I one by one convert the layer ID's to references and move them. Let me know if this works for you.



So I'm trying to integrate this with my original script, but have run into a problem.

The first part of my script creates folders/layer sets (code below), but means the previously selected layers become unselected before this part of the script is run (so your script doesn't know which layers were selected in order to move them). And if I don't create the folders then your script won't work because it can't find the target folders

Any ideas on the best way to make this work properly, and how the rest of my code (in my previous post) should fit in with it?

Applescript:

   (* Create Folders *)
   tell current document
       set artworkFolder to "Artwork"
       if exists layer set named artworkFolder then
           (* Do nothing *)
       else
           make new layer set at beginning with properties {name:artworkFolder}
       end if
       
       set colourFillFolder to "colour fill"
       if exists layer set named colourFillFolder in layer set artworkFolder then
           (* Do nothing *)
       else
           make new layer set in layer set artworkFolder with properties {name:colourFillFolder}
       end if
       
       set blendingMaskFolder to "mask"
       if exists layer set named blendingMaskFolder in layer set colourFillFolder in layer set artworkFolder then
           (* Do nothing *)
       else
           make new layer set in layer set colourFillFolder in layer set artworkFolder ¬
               with properties {name:blendingMaskFolder}
       end if
   end tell

Last edited by Jono (2018-10-15 12:22:32 am)

Offline

 

#16 2018-10-15 08:57:55 am

t.spoon
Member
From:: BFE, Massachusetts
Registered: 2013-01-13
Posts: 368

Re: Help with part of a Photoshop script?

Yes, you'll want to start by running the parts of my script up through the repeat loop that builds the list of selectedLayerIDs.

The layer ID's will not change as you create new layers, so this will be a list of what layers were selected before you do anything else and lose the selection.

Then go ahead and modify the document any way you need to - make the new folders, set the variable for moveToLayerSet to the new folder you made.

Then resume with my script for the move.


Hackintosh built February, 2012 |  Mac OS Sierra
GIGABYTE GA-Z68X-UD3H-B3 | Core i5 2500k | 16 GB DDR3 | GIGABYTE Geforce 1050 TI 4GB
250 GB Samsung 850 EVO | 4 TB RAID
Dell Ultrasharp U3011 | Dell Ultrasharp 2007FPb

Offline

 

#17 2018-10-15 11:52:43 am

Jono
Member
Registered: 2008-07-08
Posts: 95

Re: Help with part of a Photoshop script?

Thanks a lot (again)!

I managed to get it to work placing my other code where you said big_smile

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)