Issues creating a new directory and save .tifs to it

Hi All, this is my first post to this community and I have been extremely grateful for its existence! I am currently working on a macro to open .lif files, open z-stacks from them, create new subfolders within an output directory based on the name of the z-stack file, separate the color channels, and save them as .tiffs into the new subfolder directory. I’ve gotten most of this to work except when I’m trying to save the individual channel as .tiffs to the new directory I made, the files are instead saved into the original output directory and with the name of the intended subfolder tacked onto the beginning of the file name. I feel like I’m very close but I can’t seem to figure this out. Any help would be greatly appreciated!

Here is my code so far:

var outputDir // global variable to be passed to function later
var inputDir 
outputDir = File.getName(output); // retrieves the folder name string of the master input folder selected by the user above
inputDir = File.getName(input);

processFolder(input);

// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(input) {
	list = getFileList(input);
	list = Array.sort(list);
	for (i = 0; i < list.length; i++) {
		if(File.isDirectory(input + File.separator + list[i]))
			processFolder(input + File.separator + list[i]);
		if(endsWith(list[i], suffix))
			processFile(input, output, list[i]);
	}
}


function processFile(input, output, file) {
	
		// Start my macro

		print("Processing: " + input + File.separator + file);
		
		open(input + File.separator + file);
		fileTitle = getTitle();
		print("current file:", fileTitle);

		// extract well name from image file name after ".lif - " 
		wellIndex = indexOf(fileTitle, "C", 1); // index of where "C" is located in title name after the first two characters; imageJ is base 0
		wellName = substring(fileTitle, wellIndex, wellIndex + 3); // pulls out well name "C2_" or "C21", etc., the blank space will be recorded of there is one
			print("Well name:" + wellName);

		saveDir = replace(input, inputDir, outputDir); // replaces the input folder name (string) with the output folder name (string)
		saveDir = saveDir + File.separator + wellName;
		File.makeDirectory(saveDir); // makes the above directory
		print("save dir:", saveDir);
		
		run("Split Channels");
			
		if (YesCH1){ // selects the window with CH1 if CH1 is specified by user
			
			selectWindow("C1-"+ fileTitle); 
			C1title = getTitle();
			selectWindow(C1title);
			saveAs("TIFF", saveDir + C1title);
			close();
		}

		if (YesCH2){ // selects the window with CH2 if CH2 is specified by user
			
			selectWindow("C2-" + fileTitle); 
			C2title = getTitle();
			selectWindow(C2title);
			saveAs("TIFF", saveDir + C2title);
			close();
		}

		if (YesCH3){ // selects the window with CH3 if CH3 is specified by user
			
			selectWindow("C3-" + fileTitle); 
			C3title = getTitle();
			selectWindow(C3title);
			saveAs("TIFF", saveDir + C3title);
			close();
		}

}
					 
run("Close All");

I think the problem lies in here to be more precise:

selectWindow("C1-"+ fileTitle); 
			C1title = getTitle();
			selectWindow(C1title);
			saveAs("TIFF", saveDir + C1title);

Thanks!

Hi,
Looking at the code you have posted I noticed that your variables YesCH1 to YesCH3 are not actually defined at any point. The variables input and output also appear to be undefined.
I assume that there must be other code otherwise that should cause an error when you try to execute the macro.

I would also suggest not to use the same variable names for a call of a function and within the function as that can get confusing and have unexpected consequences. For example, you use processFolder(input) to call the function to process a folder and then you also use ‘input’ within the function process(), which is then passed on to another function processFile(). In your case, you might be able to get away with it as you don’t manipulate the variable ‘input’. It would be neater to use different names to keep global and local variables clearly separated. For example,
processFolder (inputDir)

function processFolder (folder){

}

Lines 3 and 4 of your code also don’t really do what is said in the comments. File.getName(path) retrieves the filename part from a path, not the directory.
For example:
print(File.getName(“C://Documents//Test//Image1.tif”));
results in ‘Image1.tif’

If you want the path, you need File.getDir(), which result in ‘C:/Documents/Test/’ for the example.

In order to see what is actually happening at the point of saving your files, have you tried to include a print(saveDir + C1title) just before the saveAs command in order to see what the actual path looks like? From your description it sounds like there is a file separator missing between your desired folder and filename.

Hope this helps,
Volko

Hi Volko,

Thanks for your response and help! I should have posted the entire code and you are correct that there is another portion of the code before this one to have the user specify input and output directories and whether or not they want to analyze channels 1,2, and or 3. Here is the code for that GUI I made:

// GUI for directory and processing options
#@ String (visibility=MESSAGE, value="<html><strong> INPUT ______________________________________________</strong><html>", required = false) msg1
#@ File (label = "Input directory", style = "directory") input
#@ File (label = "Output directory", style = "directory") output
#@ String (label = "File suffix", value = ".lif") suffix
#@ Boolean (label = "Do you want to save C1?", value = "") YesCH1
#@ Boolean (label = "Do you want to save C2?", value = "") YesCH2
#@ Boolean (label = "Do you want to save C3?", value = "") YesCH3

and the rest of the code as before:

var outputDir // global variable to be passed to function later
var inputDir 
outputDir = File.getName(output); // retrieves the folder name string of the master input folder selected by the user above
inputDir = File.getName(input);

processFolder(input);

// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(input) {
	list = getFileList(input);
	list = Array.sort(list);
	for (i = 0; i < list.length; i++) {
		if(File.isDirectory(input + File.separator + list[i]))
			processFolder(input + File.separator + list[i]);
		if(endsWith(list[i], suffix))
			processFile(input, output, list[i]);
	}
}

function processFile(input, output, file) {
	
		// Start my macro

		print("Processing: " + input + File.separator + file);
		
		open(input + File.separator + file);
		fileTitle = getTitle();
		print("current file:", fileTitle);

		// extract well name from image file name after ".lif - " 
		wellIndex = indexOf(fileTitle, "C", 1); // index of where "C" is located in title name after the first two characters; imageJ is base 0
		wellName = substring(fileTitle, wellIndex, wellIndex + 3); // pulls out well name "C2_" or "C21", etc., the blank space will be recorded of there is one
			print("Well name:" + wellName);

		saveDir = replace(input, inputDir, outputDir); // replaces the input folder name (string) with the output folder name (string)
		saveDir = saveDir + File.separator + wellName;
		File.makeDirectory(saveDir); // makes the above directory
		print("save dir:", saveDir);
		
		run("Split Channels");
			
		if (YesCH1){ // selects the window with CH1 if CH1 is specified by user
			
			selectWindow("C1-"+ fileTitle); 
			C1title = getTitle();
			selectWindow(C1title);
			saveAs("TIFF", saveDir + C1title);
			close();
		}

		if (YesCH2){ // selects the window with CH2 if CH2 is specified by user
			
			selectWindow("C2-" + fileTitle); 
			C2title = getTitle();
			selectWindow(C2title);
			saveAs("TIFF", saveDir + C2title);
			close();
		}

		if (YesCH3){ // selects the window with CH3 if CH3 is specified by user
			
			selectWindow("C3-" + fileTitle); 
			C3title = getTitle();
			selectWindow(C3title);
			saveAs("TIFF", saveDir + C3title);
			close();
		}

}
					 
run("Close All"); 

I will try to make the input and output variables more specific for each function and see if that helps with my understanding and report back. I did try to have it print the saveDir in previous versions but maybe I didn’t have it report the saveDir in the right order or place, I’ll give it another shot.

Thank you!

Hi again. I ended up simplifying the script since I wanted to perform these functions on open windows rather than on multiple images within a folder. The file separator was critical for this to work so thanks for that @Volko.

#@ File (label = "Output directory", style = "directory") output 
#@ Boolean (label = "Do you want to save C1?", value = "") YesCH1
#@ Boolean (label = "Do you want to save C2?", value = "") YesCH2
#@ Boolean (label = "Do you want to save C3?", value = "") YesCH3

print("outputDir:", output);
		
filetitle = getTitle(); // selects the next open window

wellIndex = lastIndexOf(filetitle, "- "); // index of where "- " is located in title name at the end of the string before the well name
// for example, my files consistently have the well name at the end of the file name due to the way Leica LASX names its well-plate image files: "20200825 Col gels V1.2 - C1"
wellName = substring(filetitle, wellIndex + 2); // pulls out well name "D2_" or "C21", etc., the blank space will be recorded of there is one
print("well index:", wellIndex);
print("Well name:" + wellName);

saveDir = output + File.separator + wellName; // creates a new path name under the selected output directory with the name of the wellName
File.makeDirectory(saveDir); // makes the above directory
print("save dir:", saveDir);
		
			
run("Split Channels");

if (YesCH1){
	selectWindow("C1-" + filetitle); 
	C1title = getTitle();
	saveAs("Tiff", saveDir + File.separator + C1title); // saves channel 1 of the image in the folder "wellName" under the selected output directory
	close();
}

if (YesCH2){
	selectWindow("C2-" + filetitle); 
	C2title = getTitle();
	saveAs("Tiff", saveDir + File.separator + C2title); // saves channel 1 of the image in the folder "wellName" under the selected output directory
	close();
}

if (YesCH3){
	selectWindow("C3-" + filetitle); 
	C3title = getTitle();
	saveAs("Tiff", saveDir + File.separator + C3title); // saves channel 1 of the image in the folder "wellName" under the selected output directory
	close();
}

This works very well but I have to continuously run the script manually over and over on all of the open windows until they’re all gone. I wish there was a way to have this macro loop through all the open windows in FIJI and perform these functions. I haven’t been able to find a function that just simply selects the next window. Does anyone know of a function for this?

It should be possible to wrap up all your processes into a for loop to either process all the files in a directory.
Alternatively, if you want to process a selection of images that are already open, you could use something like the code below to create an array with the names of all open images:

titles = newArray(nImages()); 
for (i=1; i<=nImages(); i++) { 
	selectImage(i); 
        titles[i-1] = getTitle(); 
};

Hope this helps,
Volko

Thanks for the tip @Volko ! I ended up finding a similar approach using the

getList("image.titles")

function as follows:

//create an array with the names of all open images
titles = getList("image.titles");
if (titles.length==0)
     print("No image windows are open");
  else {
     print("Image windows:");
     for (i=0; i<titles.length; i++)
        print("   "+titles[i]);
  
	 	print("");
  }

  for (i=0; i<titles.length; i++){
  
	 	print("processing: ", titles[i]);
	 	selectWindow(titles[i]);
		fileTitle = getTitle();

// continue the rest of my function in this loop

This works really well, thanks for the help!