Creating and moving an artLayer inside "active" layerSet

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

User avatar
StoryCave
Posts: 20
Joined: Wed Sep 21, 2016 2:14 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by StoryCave »

Actually, there might be a misunderstanding here, you've already fixed the 27th of September the background layer position movement inside the layer Set (which needs only to happen once per activeDocument - as I'll duplicate the folder for each storyboard panel -).
This was already perfect and took only 2 lines of code I understood ;)

The other issue is with my StoryCaveCam.jsx script which creates the layer with the green stroke, it works but creates the artLayer named CAM only in the top layerSet (SQ_00_SH_xxx...).
To explain how my template works, each layerSet SQ_00_SH_000_010, 020, 030, etc. will have drawings for each storyboard panel, so here's an example of what I want to do with these scripts, it'll make the project clearer :
StoryCave_Demo1.jpg
StoryCave_Demo1.jpg (147.56 KiB) Viewed 11830 times
As you can see, my current "action" creates the CAM layer on top of the Drawing layer which was the activeLayer.
If I were to use my script StoryCaveCam.jsx it would create that same layer but only in the top layerSet because the index is set to [0] even when I'm inside a bottom layerSet, like my old example where I'm initially in xxx_000 but CAM appears in xxx_010 :

Image

If there was a built-in variable called "activeLayerSet" I believe this issue would be sorted right away, but ... :/

I hope this clarifies my issue, thanks again for your help man !
User avatar
Kukurykus
Posts: 528
Joined: Mon Jul 25, 2016 12:36 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by Kukurykus »

I checked once again the post from 28 September and found I was wrong, I mean I misunderstood you. I still thought you want to move background layer to bottom of active subset, but without strict pointing it. So I wrote then another script which detected activce layer of its set and moved there background. As you see, difference was that you didn't need anymore to write where exactly background had to be moved, but a script checked it itself.

Now I know background layer issue is closed and now we're talking about creating CAM layer in a specific set - active one, without pointing it by a script - I mean a script will find it checking what layer(Set) is currently active.

Before you read my answer please reply to my question as you didn't do it before. Did that script I wrote worked for you (that with my screenshots "before" and "after" result)? So using even that simple example, moved a background inside a set where some layer was seleced as active one?

And here's a code I think you wanted about creating a CAM layer. If that is not again that you wanted then no problem, I hope we finally find the solution, as I think writing proper script is no problem for me, but only understanding what you want to exactly do... that may seem flustrating someone explains something to me quite well and though I could realize it I can't catch his mind :)

I won't create a new code. I'll use that "addition" preceding background layer part and then write 4 lines where in the 2nd eval of 3rd line I exploit PS scripting glith, so I do something what shouldn't happen if there were no bugs in Adobe Ps scrtipting environment. 2nd eval of 3rd line has to step back history state which was created by 1st eval of 3rd line, but to be honest if not a bug then 1st eval of 3rd line would create not two but just one step, so the excpected result only and nothing before it:

Code: Select all

aL = (aD = 'activeDocument') +'.activeLayer', bol = true, arr = []

while(bol) aL += '.parent', String(AL = eval(aL)).slice(1, 9) != 'LayerSet' ? bol = !bol : arr.push(AL.name)

aDl = aD + l = '.layers', n = arr.length - 1;

(function set() {
for(i = 0; i < (evl = eval(aDl)).length; i++) {
if (evl[i].name == arr[n]) {
aDl += '[i]' + l, n--, aD += l + '[' + i + ']'
if (n > -1) set(); break
}
}
})()

L = eval("(aL = activeDocument.activeLayer).kind == 'LayerKind.NORMAL' ?\
((lay = aL.parent.layers).length == 1 ? 1 : (lay[0] == aL ? 1 : 2)) : 2")
lyr = eval(aD).artLayers.add(), eval('doc.activeHistoryState =\
(hS = (doc = activeDocument).historyStates)[hS.length - L]'), lyr.name = 'CAM'
User avatar
StoryCave
Posts: 20
Joined: Wed Sep 21, 2016 2:14 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by StoryCave »

Hi Kukurykus,

To answer you question, this code still doesn't work even while selecting a layer or the group :

Code: Select all


aL = (aD = 'activeDocument') +'.activeLayer', bol = true, arr = []

while(bol) aL += '.parent', String(AL = eval(aL)).slice(1, 9) != 'LayerSet' ? bol = !bol : arr.push(AL.name)

aDl = aD + l = '.layers', n = arr.length - 1;

(function set() {
for(i = 0; i < (evl = eval(aDl)).length; i++) {
if (evl[i].name == arr[n]) {
aDl += '[i]' + l, n--, aD += l + '[' + i + ']'
if (n > -1) set(); break
}
}
})()

if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) nme = btm.name, btm.isBackgroundLayer = 0
btm.move(aD = eval(aD), ElementPlacement.PLACEATEND);(bGl = (bGn = aD.layers)[bGn.length-1]).name = nme, bGl.allLocked=1
In ExtendScript Toolkit, I get the last line (btm.move ... all.Locked=1) selected in orange.

But, to answer your second question, the code you wrote to create the CAM layer works perfectly and everything is in order ;)

A thousand thanks again, I'll update the script asap.

BTW, would you know the method to delete the last 5 historyStates ?

I've tried with :

delete(app.activeDocument.historyStates[4]);
delete(app.activeDocument.historyStates.length-4);

It doesn't show any errors but nothing happens.
The only one that works is the "purge" method I already use in the template, but clears it all :/

Thanks again !
User avatar
Kukurykus
Posts: 528
Joined: Mon Jul 25, 2016 12:36 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by Kukurykus »

I wonder why that code doesn't work for you. Maybe it's because you use PS CC while I still CS. Anyway fisrt part (that both codes have ie. with background moving and CAM creating) is identical.

It seems something brokes the code in their second part. We can investigate it some easy way. Those 2 additional lines:

Code: Select all

if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) nme = btm.name,  btm.isBackgroundLayer = 0
btm.move(aD = eval(aD), ElementPlacement.PLACEATEND);(bGl = (bGn = aD.layers)[bGn.length-1]).name = nme, bGl.allLocked=1
worked fine as separate code (that before a little change I made to connect it to a part background code and now CAM's uses). This code originally looked so:

Code: Select all

if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) nme = btm.name,  btm.isBackgroundLayer = 0
btm.move(lyr[0], ElementPlacement.PLACEATEND); (bGl = (bGn = lyr[0].layers)[bGn.length - 1]).name = nme, bGl.allLocked =1
then I added next part in front of these 2 lines while in sole 2 lines I did 2 changes, I changed a rank of nme = btm.name, btm.isBackgroundLayer = 0 for btm.isBackgroundLayer = 0; nme = btm.name adding semicolon between. Second change was changing lyr[0] in 2 spots for aD, where additionally I bound aD to eval(aD):

Code: Select all

if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) btm.isBackgroundLayer = 0; nme = btm.name
btm.move(aD = eval(aD), ElementPlacement.PLACEATEND);(bGl = (bGn = aD.layers)[bGn.length-1]).name = nme, bGl.allLocked=1

1) Now when we know this all please let's see where exactly error happens in last line (that became orange for you):

open PS, ctrl-n (new document, where only background for test is sufficient), open ESTK, set PS mode, paste a code you did before that alerted error and replace last 2 lines for these ones:

Code: Select all

if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) btm.isBackgroundLayer = 0; nme = btm.name
btm.move(aD = eval(aD), ElementPlacement.PLACEATEND);
(bGl = (bGn = aD.layers)[bGn.length-1]).name = nme, bGl.allLocked=1
2) When you do it please tell me did last or one before last line line get orange highlighted, also when you do this test, do another one but with 2 alerts:

Code: Select all

alert(aD)
if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) btm.isBackgroundLayer = 0; nme = btm.name
btm.move(aD = eval(aD), ElementPlacement.PLACEATEND);
alert(aD)
alert(eval(aD))
(bGl = (bGn = aD.layers)[bGn.length-1]).name = nme, bGl.allLocked=1
I know it's not necessary for you now, but it may help me and maybe later you to understand what happens when you will write something similar...

(ah, and just for clarity. Like CAM layer had to be created in (sub)set which (layer) was activated / selected), this code has to move last layer (changed from background if needed) to (sub)set which (layer) was activated / selected. In this (ctrl-n etc) example only background changed to layer and locked again).


3) History States Deletion:

Code: Select all

function cTT(v) {return charIDToTypeID(v)}; function sTT(v) {return stringIDToTypeID(v)}}

function HstS(v) {// UNDOING HISTORY STATES:
(ref = new ActionReference()).putOffset(cTT('HstS'), 1 - v);
(dsc = new ActionDescriptor()).putReference(cTT('null'), ref)
executeAction(cTT('slct'), dsc, DialogModes.NO);
}

function HSD() {// DELETION OF CURRENT AND FOLLOWING HISTORY STATES:
(ref = new ActionReference()).putProperty(cTT('HstS'), cTT('CrnH'));
(dsc = new ActionDescriptor()).putReference(cTT('null'), ref)
executeAction(cTT('Dlt '), dsc, DialogModes.NO)
}

HstS(5), HSD()
User avatar
StoryCave
Posts: 20
Joined: Wed Sep 21, 2016 2:14 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by StoryCave »

Hi Kukurykus,

No problem, let's do some troubleshooting.

The reason I believe it didn't work at first (apart from the version difference between CS and CC) is that I was trying to use your script using my StoryCaveTemplate.jsx file with the background layer that was already fixed and inside the layerSet at launch.

So I just stared from scratch with a new document like you suggested :

1)

When I use this code :

Code: Select all


if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) nme = btm.name,  btm.isBackgroundLayer = 0
btm.move(aD = eval(aD), ElementPlacement.PLACEATEND);(bGl = (bGn = aD.layers)[bGn.length-1]).name = nme, bGl.allLocked=1
The last line is orange and the JS console says "Result: 1", nothing happens on Photoshop.

On this code :

Code: Select all


if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) btm.isBackgroundLayer = 0; nme = btm.name
btm.move(aD = eval(aD), ElementPlacement.PLACEATEND);(bGl = (bGn = aD.layers)[bGn.length-1]).name = nme, bGl.allLocked=1
It works, no orange line, the Background layer transforms into Layer 0 (locked)

the same thing happens with this code (it works too):

Code: Select all


if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) btm.isBackgroundLayer = 0; nme = btm.name
btm.move(aD = eval(aD), ElementPlacement.PLACEATEND);
(bGl = (bGn = aD.layers)[bGn.length-1]).name = nme, bGl.allLocked=1
2)

When I use this code :

Code: Select all


alert(aD)
if ((btm = (lyr = activeDocument.layers)[lyr.length - 1]).isBackgroundLayer) btm.isBackgroundLayer = 0; nme = btm.name
btm.move(aD = eval(aD), ElementPlacement.PLACEATEND);
alert(aD)
alert(eval(aD))
(bGl = (bGn = aD.layers)[bGn.length-1]).name = nme, bGl.allLocked=1
I first have the alerts, once in ExtendScript Toolkit that says "activeDocument" and twice in Photoshop that says "[Document Untitled -1]" and then the last line becomes orange, the backgroundLayer becomes Layer 0 (no lock).

then...
I tried that same code above on my template document, I've manually put the BackgroundLayer outside the layerSet for a test then ran the code, had the same three alerts (with different names), then it put the BackgroundLayer inside the layerSet at the bottom but had the last line in orange.

3) History State Deletion

I've added the code to the StoryCaveCam.jsx script, I ran it and nothing happen except that I just deleted the extra bracket that the editor found :
bracket.jpg
bracket.jpg (7.96 KiB) Viewed 11760 times
Even after that the Result is "undefined" in the console, but i just realized I made a mistake, as I should modify the script to cut the layer, delete the history then paste it in order to work.

I'll send you an update on that asap !

Thanks again Kukurykus.

K.
User avatar
Kukurykus
Posts: 528
Joined: Mon Jul 25, 2016 12:36 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by Kukurykus »

1) I thought so you didn't include fixed part, it's why didn't work.

2) now when you found what was wrong in point 1, a code from point 2 will work too. It doesn't because I forgot to replace semicolon. When you start new 'sentence' with round bracket character then mostly everything in preceeding part need to be ended with semicolon. For example when it's ended with curly bracket then you don't need to use semicolon (but I'm not sure it's so in every case). So to make that test working you have to put semicolon after third alert expression, while that from before second alert may be removed, but nothing happens if it stays where it was put.

3) yes, I didn't remove additional bracket character after 2nd function. Originally I pasted both functions but that second wasn't needed to following code so I removed it. Then I thought maybe one day you'll need it so I pasted it again, but did mistake putting one bracket too many. If you want to check that code works simply do 5 custom things in photoshop like pressing ctrl j x 5 and then use that code, so it select -5 (it may be any other number you enter to HstS() function) history state going back from current one and then 2nd function will delete this current history state with all (already grey ones) followed.
User avatar
StoryCave
Posts: 20
Joined: Wed Sep 21, 2016 2:14 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by StoryCave »

1) indeed ;)

2) That's also what I'm trying to figure out with JavaScript syntax, in the examples I'm learning from the book Eloquent Javascript (I'm still in the beginning), the author doesn't always add curly brackets and semicolon, I need to get this right.

3) And yes it worked when I tried, thanks a lot man !

Somehow I tried to copy the CAM layer and couldn't make the code to work, here's the best I could get, but still have too many steps in the history
(ps: I put the values of the variables from the reference script in there so you don't have to import them, it works by itself if the document is 1920 by 1364) :

Code: Select all


//Set Document
var docRef = activeDocument

aL = (aD = 'activeDocument') +'.activeLayer', bol = true, arr = []

while(bol) aL += '.parent', String(AL = eval(aL)).slice(1, 9) != 'LayerSet' ? bol = !bol : arr.push(AL.name)

aDl = aD + l = '.layers', n = arr.length - 1;

(function set() {
for(i = 0; i < (evl = eval(aDl)).length; i++) {
if (evl[i].name == arr[n]) {
aDl += '[i]' + l, n--, aD += l + '[' + i + ']'
if (n > -1) set(); break
}
}
})()

//Create Camera layer
L = eval("(aL = activeDocument.activeLayer).kind == 'LayerKind.NORMAL' ?\
((lay = aL.parent.layers).length == 1 ? 1 : (lay[0] == aL ? 1 : 2)) : 2")
lyr = eval(aD).artLayers.add(), eval('doc.activeHistoryState =\
(hS = (doc = activeDocument).historyStates)[hS.length - L]'), lyr.name = "CAM"

//Set Selection
var shapeRef = [
[0,0],
[0,1364 - 284],
[1920,1364 - 284],
[1920,0]
]
docRef.selection.select(shapeRef)

//Set Stroke Color
strokeColor = new SolidColor //Default color for the camera line
strokeColor.rgb.red = 0
strokeColor.rgb.green = 165
strokeColor.rgb.blue = 63

activeDocument.selection.stroke (strokeColor, 10, StrokeLocation.INSIDE, ColorBlendMode.NORMAL, 100, false)
docRef.selection.cut()
docRef.selection.deselect()

function cTT(v) {return charIDToTypeID(v)}; function sTT(v) {return stringIDToTypeID(v)}

function HstS(v) {// UNDOING HISTORY STATES:
(ref = new ActionReference()).putOffset(cTT('HstS'), 1 - v);
(dsc = new ActionDescriptor()).putReference(cTT('null'), ref)
executeAction(cTT('slct'), dsc, DialogModes.NO);
}

function HSD() {// DELETION OF CURRENT AND FOLLOWING HISTORY STATES:
(ref = new ActionReference()).putProperty(cTT('HstS'), cTT('CrnH'));
(dsc = new ActionDescriptor()).putReference(cTT('null'), ref)
executeAction(cTT('Dlt '), dsc, DialogModes.NO)
}

HstS(3), HSD()

var idpast = charIDToTypeID( "past" );
var desc557 = new ActionDescriptor();
var idinPlace = stringIDToTypeID( "inPlace" );
desc557.putBoolean( idinPlace, true );
var idAntA = charIDToTypeID( "AntA" );
var idAnnt = charIDToTypeID( "Annt" );
var idAnno = charIDToTypeID( "Anno" );
desc557.putEnumerated( idAntA, idAnnt, idAnno );

executeAction( idpast, desc557, DialogModes.NO );
It's not really a big issue to be honest, I had to put 3 steps to delete in the history to make it work so if there's no better solution to copy and paste the CAM layer with less history steps, then let's forget about it ;)
User avatar
Kukurykus
Posts: 528
Joined: Mon Jul 25, 2016 12:36 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by Kukurykus »

I don't get what you want to do. I created new document 1920 x 1324 and played your script...

You created stroked selection, cut it, then deleted last history states to paste cut layer. You could get the same result if you stopped your script right after creating stroked selection. I don't understand why you had to delete those history states to paste earlier copied / cut layer at the end, so get the same you had meantime?

Maybe you wanted simply (literally, like you wrote) copy that created layer without cutting it (so removing, but keeping in memory)? Then you should replace cut with copy, ie. using activeDocument.selection.copy, or you asked about something else I didn't understand again? :) You may also use activeDocument.activeLayer.duplicate() instead of activeDocument.selection.copy (and then pasting ir) to finish your script in this line again without loosing your original CAM layer.
User avatar
StoryCave
Posts: 20
Joined: Wed Sep 21, 2016 2:14 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by StoryCave »

True, it's not clear and a bit messy... :oops:
At first the script stopped after the stroked selection in early versions, and it was fine.

But then I wanted to create that CAM layer with just one history state, so it doesn't clutter the cache (I often work with +50 layerSets on several psd files).

I just did the same thing with docRef.camLayer.duplicate() at the end of the script while removing the "paste in place" function but doesn't work, I added this line...

Code: Select all


var camLayer = docRef.activeLayer
...in order to identify the CAM layer I want to duplicate, but it doesn't work properly, it creates the layer but without the stroke and ends in orange.

It worked with copy() but then it has just as many states in the history.
User avatar
Kukurykus
Posts: 528
Joined: Mon Jul 25, 2016 12:36 pm

Re: Creating and moving an artLayer inside "active" layerSet

Post by Kukurykus »

So in case of one .pds document with some layerSets all works fine, but when you have many opened(?) documents where each has some layerSets that information of copied CAM layer you put to memory is in some degree lost?

Well I never worked with so many documents, especially with so many layerSets, but maybe I can help. You only need to specify some case of minimal opened documents (or there is only one at once?) and folders it contains etc so I can reproduce it and see how it (doesn't) work(s). Otherwise it's hard to me to find solution for something I can't see.