Skip to main content
MattiaVoso
Known Participant
July 25, 2018
Question

create layered image stack from files and align

  • July 25, 2018
  • 8 replies
  • 3438 views

Hi everyone,

i'm pretty new to scripting so i would really love to have some suggestions. i'm trying to code a script that does the following steps:

1.open the selected files (not from folder) in a layered photoshop stack

2. align them

3. read the shortest layer name and saves to a variable (let's call it "product")

4. create some layerset

5. saves the file to the parent directory of the source with the "product" name

6. close the file

i searched on the forum for a solution for long time but my scripting skills are too basic.

i'm not sure if it's better to do this form bridge or directly from ps.

at the moment i'm trying both the ways but don't figure out how to solve.

for the bridge script i've found some hint from this forum but this doesn't open the layered stack...

#target bridge      

/*if( BridgeTalk.appName == "bridge" ) {     

stacksToLayers = new MenuElement("command", "Stacks To Layers",  "at the end of Tools");   

}   

stacksToLayers.onSelect = function () { */

var stacks =  app.document.selections;

var stackCount = stacks.length;

for(var s = 0;s<stackCount;s++){

     var stackFiles = getStackFiles( stacks );

     if(stackFiles.length> 1){

          var bt = new BridgeTalk;

          bt.target = "photoshop";

          var myScript = ("var ftn = " + psRemote.toSource() + "; ftn("+stackFiles.toSource()+");");

          bt.body = myScript; 

          bt.onResult = function( inBT ) {myReturnValue(inBT.body); }

          bt.send(500);

     }

}

function getStackFiles( stack ){

     var files = new Array();

     for( var f = 0; f<stackCount;f++){

          files.push(stacks.spec);

          }

     return files;

};

function myReturnValue(str){

     res = str;

}

// don't have comments in the psRemote function

function psRemote(stackFiles){

     var loadLayersFromScript = true;

     var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");

     var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");

     var strFile2Stack = "Load Files into Stack.jsx";

     var ipFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strFile2Stack;

     var ipFile = new File (ipFilePath);

     $.evalFile( ipFile );

     loadLayers.intoStack(stackFiles);

     var saveFile = new File('~/desktop/'+app.activeDocument.name+'.psd');

     app.activeDocument.saveAs(saveFile);

}

//}//  app.activeDocument.close(SaveOptions.DONOTSA

VECHANGES);

from debugging it stops on bt.send(500); line repeating this command....

$.level = 0; app.synchronousMode = false;

on the ps script part i have similar issue, the layered files doesn't open... here the code

var fileList= File.openDialog("seleziona i files",undefined,true);

    for (i = 0; i <= fileList.length-1; i++) { 

        alert(fileList.path + "/" +fileList.name);

        // or open or do somethig else 

        }

if ( fileList != null ){

runLoadStack();

}

function runLoadStack( fileList ){

    var loadLayersFromScript = true;// must be set before the include

    // @include '/C/Program Files/Adobe/Adobe Photoshop CC 2017/Presets/Scripts/Load Files into Stack.jsx'

    var aFlag = true;

    loadLayers.intoStack( fileList, aFlag );

}

the other parts of the script i should be able to manage...

anyone could help me?

thank you a lot and a great hug form Italy

Alessio

This topic has been closed for replies.

8 replies

MattiaVoso
Known Participant
July 26, 2018

is there a way to save the file in tif format to the parent directory?

i've tryed

aD.saveAs(File(decodeURI(v[0]).slice(0, -3).parent + '.tif'))

but is not working..

anyway thanks a lot for your time and experience. Hope to see the results of all this efforts!

Don't know supermerlin, but of course you know what you're doing

Kukurykus
Legend
July 26, 2018

I think it can be changed to .tif on the condition you will use tif options which you store to tif variable and then use this:

aD.saveAs(File(decodeURI(v[0]).slice(0, -3) + 'tif'), tif)

You can actually set default resolution to 300 in this Bridge part of script:

w = m().width, h = m().height, x = m().xResolution || 300

As I said in post with original script that's not done yet. Now after you tested it and suggested some changes, I'll write them.

MattiaVoso
Known Participant
July 30, 2018

Hi,

hope this finds you well!!

do you think you are going to work on this in the next days? if not i wil try to make the changes, let's see what happens

anyway thank you again for your efforts

MattiaVoso
Known Participant
July 26, 2018

I tried the older version of the script with other stacks and everything is working correctly... actually the problem was with the pictures i used to test it.. never thought about this

i think you are a great programmer, for real!

Kukurykus
Legend
July 26, 2018

What's wrong with pictures you used for test, why they don't have resolution? What is difference between them and regular ones? Can you also check my last post - I updated it. Regarding being great programmer - I think SuperMerlin is greater

MattiaVoso
Known Participant
July 26, 2018

sorry i wrote too fast

it also saves the psd in the same folder with 2 layers inside a layerset

GREATTTTT

MattiaVoso
Known Participant
July 26, 2018

the first ps code opens a new document of 1000x1000px

the second bridge code interrupts at the moment of alert. no message boxes apperars.....

Kukurykus
Legend
July 26, 2018

There is one closing parenthesis too many, and actually that is not latest version Sorry again - I edited my last message right after I posted it. Becuase I did it fastly I thought I don't have to say about edit. Unfortunately you was faster and used old code with mistake. So please step back to that previous post of me and use changed version

MattiaVoso
Known Participant
July 26, 2018

faster and faster

thank you

now 3 alerts comes with

1000

1000

0

MattiaVoso
Known Participant
July 26, 2018

and i'm on windows too

MattiaVoso
Known Participant
July 26, 2018

dear kukurykus i really thank you again for your efforts.

i actually can't see the numbers of fjile dimensions and res. i can see only alert(1) wich is the first i put before the document.add...

after that, ANY message box appear, so no dimensions and no resolutions...

really don't know what to say

i use both bridge and ps cc 2018

Kukurykus
Legend
July 26, 2018

I'm sorry, my fault I didn't notice I put 2 diferent alert(1) in that snippet

So the problem is either with documents.add() method or dimension and resolution that weren't stored to object, but needed to create new document. Let's test which of these don't work correctly.

Try it in ExtendScriptToolKit with targeted Photoshop (without script):

#target photoshop

displayDialogs = DialogModes.NO

preferences.rulerUnits = Units.PIXELS

documents.add(1000, 1000, 300)

In our script this time replace:

for(i = 0; i < v.length; i++) {

     documents.add((whx = v[v.length - 1]).w, whx.h, whx.x)

     for(j = 0; j < v.length - 1; j++) openingAlligningSaving(v);

to this:

for(i = 0; i < v.length; i++) {

     alert((whx = v[v.length - 1]).w)

     alert(whx.h), alert(whx.x), documents.add(1000, 1000, 300)

     for(j = 0; j < v.length - 1; j++) openingAlligningSaving(v);

...and tell me were you able to create new document, and see content of all alerts?

MattiaVoso
Known Participant
July 26, 2018

with this i can see only alert (1)

for(i = 0; i < v.length; i++) { 

        alert(1);

     documents.add((whx = v[v.length - 1]).w, whx.h, whx.x), alert(whx.w + ' ' + whx.h + ' ' + whx.x)  ;

     for(j = 0; j < v.length - 1; j++) alert(1), openingAlligningSaving(v), alert(2);

Kukurykus
Legend
July 26, 2018

So you saw file dimension and resolution in that first alert - I mean they weren't like only zeros but normal numbers?

It seems 'placeEvent' doesn't work for you. For me it does both in CS6 EXTENDED and CC2018. Which one do you have, is it latest one? Let's see if it's failing when you use only this function preceded by creating document.

(Notice I used File('~/desktop/someFile.jpg') so create the same on your desktop or change a path to other file)

function sTT(v) {return stringIDToTypeID(v)}

function openingAlligningSaving(v) {

     (dsc1 = new ActionDescriptor()).putPath(sTT('null'), File('~/desktop/someFile.jpg'))

     dsc1.putEnumerated(sTT('freeTransformCenterState'), sTT('quadCenterState'), sTT('QCSAverage'));

     (dsc2 = new ActionDescriptor()).putUnitDouble(sTT('horizontal'), sTT('pixelsUnit'), 0)

     dsc2.putUnitDouble(sTT('vertical'), sTT('pixelsUnit'), 0)

     dsc1.putObject(sTT('offset'), sTT('offset'), dsc2)

     executeAction(sTT('placeEvent'), dsc1)

}

displayDialogs = DialogModes.NO, preferences.rulerUnits = Units.PIXELS

documents.add(1000, 1000, 300), openingAlligningSaving()

Btw are you on Windows or MacOS, maybe here is a problem - I mean that how path is interpreted. I'm Windows user.

Kukurykus
Legend
July 25, 2018

1) would you like process be automated for more than one stack that are content of same folder or for one at once?

2) if I understand you don't want files from Bridge stack to be placed into Smart Object but collected into layerSet?

3) do you want first file from the Bridge stack was a source position for aligning all next ones to its top left corner?

4) should layerSet have some specific name, maybe like 'Stack' or the shortest layer name, so like new file name?

MattiaVoso
Known Participant
July 25, 2018

Dear Kukurykus

thank you for your answer

1) just once at once since i have several files of different stacks in the same folder

2) yoes, correct, i want it in layer set

3)i would like to use the Autoalign function of photoshop

4) the layerset should have a generic name like "montage"

hope i answer well to your qestions

Kukurykus
Legend
July 26, 2018

That's complete but not finished yet script It generally works, but you may suggest what to change to adjust it to your expectations. I made easier version of imitating Photoshop Stack. That's generally the same but can be changed to that you'll say. I did it originally with Autoalign, but for some reason it didin't work for all opened files during my tests so I replaced it with some simpler version that do the same. There is resizing image part to correct as it rather fits similary dimensioned images what should be of course changed. Ah and I didn't cover yet folders that  can be included in stacks.

Regarding Bridge part I didn't have time yet to make it will process only chosen stack(s). So if there are more than one in the same folder it's going to process all of them, one by one and then save each in the same folder as .psd with a name of top layer: Don't worry later I will change it. For now just test it and say how it works for you and what should be changed.

Ah - you run it from Bridge! So you open some folder with stacks then load script from ExtendScript ToolKit. Of course I'm going to do it pernament that will stay in Br with each open. For now it's more like test version however in 80% finished:

#target bridge

if (sLen = (stck = (ad = app.document).stacks).length) {

     ad.chooseMenuItem('CollapseAllStacks')

     for(arr = Array(sLen), i = 0; i < sLen; i++) {

          arr = [], tLen = (img = stck.thumbnails).length

          for(j = tLen - 1; j >= 0; j--) arr = img.spec

          m = function() {return img[0].core.quickMetadata}

          w = m().width, h = m().height, x = m().xResolution

          r = !((Math.abs(new Thumbnail(arr[0]).rotation / 90) + 2) % 3)

          if (r) h = ([w = h, m().width])[1]; arr[tLen] = {w: w, h: h, x: x}

     }

}

function Ps(v) {

     function openingAlligningSaving(v) {

          (dsc1 = new ActionDescriptor()).putPath(sTT('null'), v)

          dsc1.putEnumerated(sTT('freeTransformCenterState'), sTT('quadCenterState'), sTT('QCSAverage'));

          (dsc2 = new ActionDescriptor()).putUnitDouble(sTT('horizontal'), sTT('pixelsUnit'), 0)

          dsc2.putUnitDouble(sTT('vertical'), sTT('pixelsUnit'), 0)

          dsc1.putObject(sTT('offset'), sTT('offset'), dsc2)

          executeAction(sTT('placeEvent'), dsc1)

     }

     function sTT(v) {return stringIDToTypeID(v)}

     (ref1 = new ActionReference()).putProperty(sTT('property'), sTT('generalPreferences'))

     ref1.putEnumerated(sTT('application'), sTT('ordinal'), sTT('targetEnum'));

     (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1);

     (dsc2 = new ActionDescriptor()).putBoolean(sTT('placeRasterSmartObject'), false)

     dsc1.putObject(sTT('to'), sTT('generalPreferences'), dsc2)

     executeAction(sTT('set'), dsc1)

     prf = preferences.rulerUnits, preferences.rulerUnits = Units.PIXELS

     for(i = 0; i < v.length; i++) {

          documents.add((whx = v[v.length - 1]).w, whx.h, whx.x)

          for(j = 0; j < v.length - 1; j++) openingAlligningSaving(v);

          (aD = activeDocument).selection.selectAll();

          (ref1= new ActionReference()).putEnumerated

          (sTT('layer'), sTT('ordinal'), sTT('targetEnum'));

          (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)

          executeAction(sTT('selectAllLayers'), dsc1);

          /* TEMPORARY */(function algn(v1, v2) {

          dsc1.putEnumerated(sTT('using'), sTT('alignDistributeSelector'),

          sTT(v1)), executeAction(sTT('align'), dsc1); if (v2) algn('ADSLefts')

          })('ADSTops', true);/* TEMPORARY */

          (ref2 = new ActionReference()).putClass(sTT('layerSection'));

          (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref2);

          dsc1.putReference(sTT('from'), ref1), executeAction(sTT('make'), dsc1)

          dsc1.putReference(sTT('null'), ref1);

          (dsc2 = new ActionDescriptor()).putString(sTT('name'), 'Set')

          dsc1.putObject(sTT('to'), sTT('layer'), dsc2)

          executeAction(sTT('set'), dsc1, DialogModes.NO)

          aD.selection.deselect(), aD.backgroundLayer.remove()

          aD.saveAs(File(decodeURI(v[0]).slice(0, -3) + 'psd'))

          aD.close(SaveOptions.DONOTSAVECHANGES)

          /*

          (ref = new ActionReference()).putEnumerated

          (sTT('layer'), sTT('ordinal'), sTT('targetEnum'));

          (dsc = new ActionDescriptor()).putReference(sTT('null'), ref )

          dsc.putEnumerated( sTT('using'), sTT('alignDistributeSelector'), sTT('ADSContent'))

          dsc.putEnumerated( sTT('apply'), sTT('projection'), sTT('perspective')), executeAction(sTT('align'), dsc)

          */

     }

     preferences.rulerUnits = Units.PIXELS = prf

}

arr = arr.toSource(), (bT = new BridgeTalk()).target = 'photoshop',

bT.body = Ps.toString() + '\nPs(' + arr + ')', bT.send()