Template is missing File.separator since updated with Script Parameters

script-editor
code-templates
scriptparameters
fiji
Tags: #<Tag:0x00007fd546e20e78> #<Tag:0x00007fd546e20c20> #<Tag:0x00007fd546e20a18> #<Tag:0x00007fd546e208b0>

#1

In Fiji, the current IJ1 “Process Folder” script template is a bit misleading as the “Input directory” script parameter does not return a path with a trailing slash while the previous getDirectory() approach did.

The code works, but it might be confusing to someone learning. As a result, it might be worth changing:
print("Processing: " + input + file);
to:
print("Processing: " + input + File.separator + file);


Batch Processing Several Folder
#2

I’m on it @dnmason… thanks for the input on this!

https://github.com/imagej/imagej-legacy/commit/d685ea0b81b88b74850c29de5af9dc33080738ef

eta :slight_smile:


#3

Just for reference, we had a “discussion” on the topic of trailing slashes with #@File and getDirectory() in:


#4

Thanks for the speedy work!


#5

Sorry for not spotting this before but to make the recursive work you also need the File.separator on at least the second but maybe the first and second lines:

	if(File.isDirectory(input + list[i]))
		processFolder("" + input + list[i]);

Subdirectories are never processed without it.


#6

@dnmason

Good catch! I can’t believe we never saw that before… oops!

Then the code example would be something like this:

// @File(label = "Input directory", style = "directory") input
// @File(label = "Output directory", style = "directory") output
// @String(label = "File suffix", value = ".tif") suffix

/*
 * Macro template to process multiple images in a folder
 */

// See also Process_Folder.py for a version of this code
// in the Python scripting language.

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) {
	// Do the processing here by adding your own code.
	// Leave the print statements until things work, then remove them.
	if(endsWith(input, File.separator))
		print("Processing: " + input + file);
	else 
		print("Processing: " + input + File.separator + file);
        print("Saving to: " + output);
}

It’s a bit clumsy at the end… but fixes the issue.

eta


#7

Which fix would people prefer for the processFolder() function example?

Function #1

function processFile(input, output, file) {
	// Do the processing here by adding your own code.
	// Leave the print statements until things work, then remove them.
	if(endsWith(input, File.separator))
		print("Processing: " + input + file);
	else 
		print("Processing: " + input + File.separator + file);
    print("Saving to: " + output);
}

Function #2

function processFile(input, output, file) {
	// Do the processing here by adding your own code.
	// Leave the print statements until things work, then remove them.
	if(endsWith(input, File.separator))
		input = substring(input, 0, (lengthOf(input)-1));
	print("Processing: " + input + File.separator + file);
    print("Saving to: " + output);
}

[poll public=true]

  • Function #1
  • Function #2[/poll]

(I know this polling is not really necessary… but it was fun to make!!)


#8

@dnmason

You know what?! We are most likely the only two who will respond to this… since I have no extreme preference in the end… we’ll go with your preferred version. :slight_smile:

It’s fixed here!

https://github.com/imagej/imagej-legacy/commit/9971b2a5a870b2b8bb99779f24fb22ec1e804422

eta


#9

I vote for keeping the template simpler:

function processFile(input, output, file) {
	// Do the processing here by adding your own code.
	// Leave the print statements until things work, then remove them.
	print("Processing: " + input + File.separator + file);
	print("Saving to: " + output);
}

At worst, there will be multiple consecutive slashes, which is tolerated on POSIX-friendly systems as well as on Windows.


#10

@ctrueden

Agreed. There is always a compromise… but ‘simpler’ is better in this case…

It’s fixed accordingly.

eta :slight_smile:


#11

Ahh, I didn’t fully appreciate why you included the substring function, but I now see. Not a huge problem I guess. Thanks again for the quick response.


#12

Agreed.

Moreover, @etarena your solution wouldn’t have worked at all as intended on Windows, as getFileList returns directory names with a trailing slash (/) whereas File.separator is a backslash (\) on that platform.

BTW, we should really have a unit test for these macro and script templates!


IMHO, the “evil” is in the getFileList macro function, as it returns some non-standard (but at least OS-independent) string for directory names. But since there are checks for endsWith('/') in many places in IJ1 land, this will stick around.
As long as it works fine and double separators are tolerated in IJ1 Macro language, all is well…


#13

I only found a problem if you try to run a selectWindow() as it ends up with an extra slash in title, but once you realise that you can code around it.

I think the important thing (as mentioned above) is having the proof of principal clear for someone learning.


#14

I don’t get your point. If you do:

open(input + File.separator + file);

you won’t end up with trailing slashes in the image title, will you? I.e. selectWindow(file) would still work, no?


#15

Sorry for the lack of clarity, I think it may actually be something in my script. The input of the subdirectory has a trailing slash, so if you include a file separator, you get something like:

c:\path\to\my\file\subdirectory/\myfilename.tif

For reasons (at present) unbeknownst to me, the title became \myfilename.tif .Not to worry though, the script needs an overhaul anyway, I just was hoping to add a quick couple of lines to deal with recursive directories.


#16

Oh, now I see :slight_smile:, thanks for clarifying!

That would be an argument for me to switch to a “real” scripting language (while I still acknowledge the advantages of the macro language in terms of recording and quick prototyping, of course…)

You might be interested in the batch-processor project I’m working on (and hope to have a more stable version on some update site within a month or so). The goal is to separate the concerns of batch processing from the functionality of any given script, by using script parameters:

  • The script is annotated with a #@File or #@ImagePlus input and takes care of processing a single file or image
  • The batch processor wraps around any “batchable” script by feeding any list of files (e.g. recursively from folders) to the respective inputs, and filling the remaining script parameters once for all by generating the usual dialog.

#17

Not the first time I’ve heard that :slight_smile:

Really like the sound of batch-processor, will definitely have a look, thanks for the mention.