/*
 * Finds all Xradia image files (tomographic projections and reconstructed slices) 
 * in a folder and subfolders, and generates a single preview .png image 
 * and a .txt file containing some image metadata. 
 * For reconstructed slices, it makes an X-Y-Z preview montage, and 
 * for projection files it makes a montage of the first and middle projections
 * (for a 180 deg. scan this will be 0 and 90 degree views).
 * These are saved with the same filename base as the original.
 * Requires the ImageJ plugin XRM_Thumbnails, as modified by B. Metscher.
 * Version 7.0, last updated Dec. 2024
 */

#@ File (label = "Input directory", style = "directory") input
// Use the input directory as the output directory 

processFolder(input);
print("\n" + "Finished with " + input + "." + "\n");

 // function to scan folders/subfolders/files to find files with correct suffixes
function processFolder(input) {
	list = getFileList(input);
	list = Array.sort(list);	

	for (i = 0; i < list.length; i++) { 
		filePath = input + File.separator + list[i];
		CurrentFile = File.getDirectory(filePath) + list[i];  //removes extra file separator (maybe)
			if (File.isDirectory(CurrentFile)) { 
			processFolder(CurrentFile);
		}	else {
			 // For each .txm, .xrm and .txrm file in directory, but skip reference and drift images
			isTXRMfile = endsWith(list[i], ".txrm");  // projection images
			isXRMfile = endsWith(list[i], ".xrm");	
			isTXMfile = endsWith(list[i], ".txm");	// reconstructed slices
			
			if (isTXRMfile || isXRMfile || isTXMfile) {  // skip recently thumbnailed files
				if (isTXRMfile) { 
					oldPNG = replace(CurrentFile, ".txrm", ".png");
					oldTxt = replace(CurrentFile, ".txrm", ".txt");
				}
				if (isXRMfile)  { 
					oldPNG = replace(CurrentFile, ".xrm", ".png");
					oldTxt = replace(CurrentFile, ".xrm", ".txt");
				}
				if (isTXMfile) {
					oldPNG = replace(CurrentFile, ".txm", ".png");
					oldTxt = replace(CurrentFile, ".txm", ".txt");
				}					
				alreadyDone = (File.exists(oldPNG) && File.exists(oldTxt));  
				isXtraFile = (list[i].contains("_Drift"))||(list[i].contains("_Ref")); // skip ref & drift files
				FileSize = File.length(CurrentFile);	// ignore ~empty files
				if (!alreadyDone && !isXtraFile && FileSize>250000) processFile(CurrentFile); 	
			}
		}
	}
}

function processFile(CurrentFile) {
//	opens the selected file using a special version of the XRM reader plugin
	setBatchMode(true);		
		//Open the file using the Only4_ThumbsMacro plugin, which is not meant to run separately. 
		//Square brackets retain spaces in path and filenames		
	run("XRM_Thumbnails", "load=[" + CurrentFile + "]"); 
	if (nImages>0) {
		stackID = getImageID(); //stack is open, get its ID
		getDimensions(width, height, channels, slices, frames);		
	
		if (isTXRMfile) {  //save first and middle projections as a preview image  
			  // requires that the plugin return a stack with 2 images
			run("Make Montage...", "columns=2 rows=1 scale=1 border=5");	// displayed despite batch mode
			setOption("ScaleConversions", true);  // seems necessary for converting to 8-bit
			run("Enhance Contrast", "saturated=0.35");  //brightness & contrast may need adjustment 
			run("8-bit");  
			saveAs("png", File.getDirectory(CurrentFile) + File.nameWithoutExtension);
			while (nImages>0) close();
	 	
		} else if (slices==1) {  //save the image as a preview (8-bit PNG) 
	 	 	run("Duplicate...", "title=Snapshot");
			run("Enhance Contrast", "saturated=0.35");  //brightness & contrast may need adjustment 
			run("8-bit");
			saveAs("png", File.getDirectory(CurrentFile) + File.nameWithoutExtension);
			while (nImages>0) close();
			
		} else {  // make a thumbnail image of X Y Z slices, for recon (.txm or .xrm) stacks
			halfW = round(width/2);
			halfH = round(height/2);
			setBackgroundColor(255, 255, 255);  // use white to separate panels in the montage
			setOption("ScaleConversions", true);  // seems necessary for converting to 8-bit

			setTool("line");    // make YZ reslice
			makeLine(halfW, 0, halfW, height);
			run("Reslice [/]...", "output=1.000 slice_count=1 avoid");
			run("Enhance Contrast", "saturated=0.35");  //brightness & contrast may need adjustment 
			run("8-bit");  
			if (getWidth() > getHeight()) run("Rotate 90 Degrees Right"); //orient vertically
			newWidth = getWidth()+5;  //add a white separator between images in the montage
			newHeight = getHeight();
			run("Canvas Size...", "width=newWidth height=newHeight position=Center-Right");
			rename("YZ_slice"); // change window title (reslices get the same name)
			
			selectImage(stackID);  	// make XZ reslice
			setTool("line");
			makeLine(0, halfH, width, halfH);
			run("Reslice [/]...", "output=1.000 slice_count=1 avoid");
			run("Enhance Contrast", "saturated=0.35");  //brightness & contrast may need adjustment 
			run("8-bit");
			if (getWidth() > getHeight()) run("Rotate 90 Degrees Right"); //orient vertically
			newWidth = getWidth()+5;  //add a white separator between images in the montage
			newHeight = getHeight();
			run("Canvas Size...", "width=newWidth height=newHeight position=Center-Right");
			rename("XZ_slice"); // change window title (reslices get the same name)
			
			selectImage(stackID);  // make XY mid-stack slice 
			setSlice(round(slices/2));
			run("Duplicate...", "ignore title=XY_slice");
			selectImage("XY_slice");
			run("Enhance Contrast", "saturated=0.35");  //brightness & contrast may need adjustment 
			run("8-bit");

			selectImage("XY_slice");  // make montage and save as TIFF
			run("Combine...", "stack1=XY_slice stack2=[XZ_slice]");
			run("Combine...", "stack1=[Combined Stacks] stack2=[YZ_slice]");
			saveAs("png", File.getDirectory(CurrentFile) + File.nameWithoutExtension);
			while (nImages>0) close();	
		}
	}
	setBatchMode(false);
	
}
