Skip to main content
daniell11223644
Known Participant
August 30, 2020
Question

Load files into stack - Automate stacking into smaller groups of images.

  • August 30, 2020
  • 3 replies
  • 4842 views

I would like to find a way to segment my stacks automatically. For example. If I am stacking very large images, or have a folder of 100 images I would like to stack, I can run into disk space issues from the paging file and scratch disk etc. As well as not knowing if its frozen etc when processing that many images.

 

So Id like to say be able to break up the stacking into 4 images or x number of images at a time, provide Photoshop with a list of 100 or other large number of images, have Photoshop take the first 4 images, auto-align them, convert to smart object, set the stack mode, rasterise the smart object, save the image and close etc, then do the same for the next 4 images and so on until it works through the list of images.

 

Then take the resulting saved images and recursively do this until 1 final image is saved. I do not fancy having to do 4 at a time by hand and having to wait each time when I could just let it go and do something else during that time.

 

How would I go about this?

This topic has been closed for replies.

3 replies

daniell11223644
Known Participant
August 30, 2020

Okay, my script is working now as I want it, I tested it on a set of 13 files, and set the stacknumber to 4. It stacks 3 groups of 4 images, ignores the last image, and saves 3 tiff files, then loops and stacks the remaining 3 tiff files together, saves a file, then saves a duplicate labelled FINAL_STACK to show which one it is. Work in progress, but I hope to automatically calculate the ideal stack number given a maximum stack number based on the number of images to minimise unused images.

 

var folder = new Folder('D:/RAW Compare/teststack');
var flist1 = folder.getFiles('*.tif');
//flist1.length = number of items
var stackDepth = 0;
var totalStackCount = 0;
var stackNumber = 4; //how many images to stack at once, you should make sure your files are evenly divisible by this
var recurseDepth = 0;

cTID = function(s) { return cTID[s] || (cTID[s] = app.charIDToTypeID(s)); };
sTID = function(s) { return app.stringIDToTypeID(s); };

const deleteRecursives = true; //delete recursive stacked images once they are finished



function runLoadStack(fileList) {
    var loadLayersFromScript = true;
    // @include 'Load Files into Stack.jsx'
    //var fList = folder.getFiles('*.tif')
	var aFlag = true;
	//alert(fileList.length + " " + typeof(fileList));
	loadLayers.intoStack(fileList, aFlag);
    loadLayers.alignStack = function( stackDoc ){
		selectAllLayers(stackDoc, 0);
	}

    
}

function selectAllLayers2() {
		var ref = new ActionReference();
		ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID('Trgt'));
		var desc = new ActionDescriptor();
		desc.putReference(cTID('null'), ref);
		executeAction(sTID('selectAllLayers'), desc, DialogModes.NO);
	}

function createSmartObject(){
    var idnewPlacedLayer = stringIDToTypeID( 'newPlacedLayer' );
    executeAction(idnewPlacedLayer, undefined, DialogModes.NO);
}

function changeStackMode(){ //set stack mode to median
	var idapplyImageStackPluginRenderer = stringIDToTypeID( "applyImageStackPluginRenderer" );
    var desc3 = new ActionDescriptor();
	var idimageStackPlugin = stringIDToTypeID( "imageStackPlugin" );
    var idmedn = charIDToTypeID( "medn" );
    desc3.putClass( idimageStackPlugin, idmedn );
    var idNm = charIDToTypeID( "Nm  " );
    desc3.putString( idNm, """Median""" );
	executeAction( idapplyImageStackPluginRenderer, desc3, DialogModes.NO );
}

function rasteriseObject(){
	var idrasterizeAll = stringIDToTypeID( "rasterizeAll" );
	executeAction( idrasterizeAll, undefined, DialogModes.NO );
}

function saveNewTiff(fin){
	var doc = app.activeDocument;
	var fileName = File.decode(doc.name);
	var n = fileName.lastIndexOf(".");
	if (n > 0) fileName = fileName.substr(0, n);
	var d = new Date();
	if (fin==true){fileName="FINAL_STACK_"; }
	fileName += "_" + ("00" + d.getHours()).slice(-2) + "_" + ("00" + d.getMinutes()).slice(-2)+"_"+("00" + d.getSeconds()).slice(-2) + ".tif";
	fileName = folder + "/" + fileName
	//saveTiff(fileName)
	//alert(folder+fileName);
	return saveTiff(fileName);
}

function saveTiff(filename){
	tiffFile = new File(filename);
	tiffSaveOptions = new TiffSaveOptions();   
	tiffSaveOptions.embedColorProfile = true;   
	tiffSaveOptions.alphaChannels = true;   
	tiffSaveOptions.layers = true;  
	tiffSaveOptions.imageCompression = TIFFEncoding.NONE;  
	//alert(filename);
	activeDocument.saveAs(tiffFile, tiffSaveOptions, true, Extension.LOWERCASE);   
	return tiffFile;
}

function closeDocument(forceNotify){
	var s2t = function (s) {
		return app.stringIDToTypeID(s);
	};

	var descriptor = new ActionDescriptor();

	descriptor.putEnumerated( s2t( "saving" ), s2t( "yesNo" ), s2t( "no" ));
	descriptor.putInteger( s2t( "documentID" ), 482 );
	descriptor.putBoolean( s2t( "forceNotify" ), forceNotify );
	executeAction( s2t( "close" ), descriptor, DialogModes.NO );
}

function fixFilename(filename){

	filename.splice(0,1); //remove leading forward slash
	var drive = filename.slice(0,1);
	drive = drive.toUpperCase();
	filename.splice(0,2); //remove drive letter and slash
	filename = drive + ":/" //fixed
	return filename;
}

if (flist1.length > 1){
	//check enough files for stacknumber
	if (flist1.length < stackNumber){
		stackNumber = flist1.length //under recursive stacking, this should ensure that final files are stacked
	}
	var i;
	var wflist = new Array(); //working file list to split up work load
	var nflist = new Array(); //folder.getFiles("*.tif"); //use this to build list of saved files for recursive 
	var deletelist = new Array();
	
	//nflist.splice(0,nflist.length);

	while (flist1.length > 1){
		//shorten list of files

		
		for (i = 0; i < stackNumber; i++){
			wflist[i] = flist1[i];
		}
		//alert((wflist[0]));
		//load files into stack
		runLoadStack(wflist);
		totalStackCount += wflist.length;
		//select all layers
		selectAllLayers2();
		//auto align
		//
		//convert to smart object
		createSmartObject();
		//set stack mode to median
		changeStackMode();
		//rasterise smart object
		selectAllLayers2();
		rasteriseObject();
		//save a file, add new file to nflist
		tempfile = saveNewTiff(false); //save new tiff and return filename 
		
		nflist.push(tempfile);
		//alert(nflist.length);
		//deletelist.push(tempfile2);
		

		
		//clear working file list array
		wflist.splice(0,wflist.length);
		//delete the files from full file list already stacked
		flist1.splice(0, stackNumber); //should start at 0 and remove number of files stacked
		stackDepth += stackNumber; //increase current stack depth by the number of files stacked
		if (flist1.length < stackNumber){ //If we dont have enough files for stack number and its not final set of files then dont include them
			flist1.splice(0,flist1.length);
			//if we're finished, then repopulate the original file list using our saved stacked files
			for (j=0; j<nflist.length; j++){ //copy array item by item
				//nflist[j] = fixFilename(nflist[j]);
				flist1[j] = new File(nflist[j]);
			}
			if (nflist.length < stackNumber){ stackNumber = nflist.length; }
			nflist.splice(0,nflist.length)
			//flist1 = nflist.getFiles();
			//alert(typeof(flist1));
			//alert(typeof(nflist));
		}
		
		//close file
		if ( flist1.length <= 1){
			saveNewTiff(true);
			//delete temp files if possible
		}
		closeDocument(true);
	}
	m = "Files Stacked: " + totalStackCount + " nflist: " + nflist.length + " wflist: " +wflist.length + " flist1: " + flist1.length + " dfiles: " + deletelist.length;
	alert(m);
}
JJMack
Community Expert
Community Expert
August 30, 2020

 

If you ar Processing normal Image file I think You should stack them all with Load Layers into a stack.  Recursively process them is small groups I believe will develop problem.  If its a resource capasity problem larger groups may worm.

 

theFiles = inputFolder.getFiles(/\.(nef|cr2|crw|dcs|raf|arw|orf|dng|psd|tif|jpg|png)$/i);

JJMack
daniell11223644
Known Participant
August 30, 2020

takes too much space doing it all at once, and can freeze or hang. Ive done it manually before for 100 images but sub dividing the stacking groups such as 4 lots of 25 then stacking the remaining 4, or 10 lots of 10, then the remaining 10, the number is arbitrary as long as I evenly divide it into the number of images. Results always worked out well.

 

For example, what code do I need to select all layers, convert to a smart object, set the stack mode.  selectAllLayers seems to be an undefined function when I try to use it in my code

JJMack
Community Expert
Community Expert
August 30, 2020

Many things  you can do in Photoshop can not be scripted using Adobe Photoshop DOM code for there no method for that feature in Adobe Photoshop DOM.   However if the Step you want to do can be recorder or inserhed into am Action.  You can user Action Manager script code.  Adobe even supplies a Plug-in the will log Action mamagers code into two logs one you desktop A VSB Log and a JavaScript Log.  The code is not very readanle the thet is a JavaScript "Clean SL.jsx" the can process the JavaScript  clean the code int a more readable fone of Code and Functions.

 

Menu Select>Select All layers will target all visible layer but the background layer.

 

The Scriptlistenes code will look like this:

 

// =======================================================
var idselectAllLayers = stringIDToTypeID( "selectAllLayers" );
    var desc8 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref1 = new ActionReference();
        var idLyr = charIDToTypeID( "Lyr " );
        var idOrdn = charIDToTypeID( "Ordn" );
        var idTrgt = charIDToTypeID( "Trgt" );
        ref1.putEnumerated( idLyr, idOrdn, idTrgt );
    desc8.putReference( idnull, ref1 );
executeAction( idselectAllLayers, desc8, DialogModes.NO );

 

 

Cleaned up by "Clean SL.jsx"  the code looks like this:

 

// =======================================================
selectAllLayers();
function selectAllLayers() {
	var descriptor = new ActionDescriptor();
	var reference = new ActionReference();

	reference.putEnumerated( stringIDToTypeID( "layer" ), stringIDToTypeID( "ordinal" ), stringIDToTypeID( "targetEnum" ));
	descriptor.putReference( charIDToTypeID( "null" ), reference );
	executeAction( stringIDToTypeID( "selectAllLayers" ), descriptor, DialogModes.NO );
}

 

 

 

 

JJMack
JJMack
Community Expert
Community Expert
August 30, 2020

Load layers into a stack is a Photoshop script that has an interactive Dialog that you build up a file list then click on the Dialog OK button. The script will then Process the File List you put together in the scripts dialog into a new document layers stack. 

 

The script has a function to load a file list into a new documents layer stack.   

 

So if you a have folder of Image files that you want to load into new documents that contain  5 Images in each new document You should be able to write a  Photoshop  that would have you  select the Folder of Images you want stacked.  The Script would get the list of Image files  that Photoshop Support or just the Image file types you want to stack. Once it has the list it would the process files file from the list at a time with Load Files into a Stack function that loads a list of file into a new document layers stack an theb doe youe other processing.[" convert to smart object, set the stack mode, rasterise the smart object"].  The script could leave these new documents open in photoshop or save PSD files to an output folder and closet the new document.  It also look like the function supports an Align flag. So you also have that as an option... Here the function in Adobe Loads files into a Stack script line 107

 

JJMack
daniell11223644
Known Participant
August 30, 2020

Ive never scripted in Photoshop before, so I have no idea what to do with that