Login  Register

isOpen("path") ?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options Options
Embed post
Permalink
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

isOpen("path") ?

vischer
Is there a simple way to check if a stored image is open?
For example,

   isOpen("/Users/norbert/Desktop/blobs.gif")

would be nice, but seems not to be supported, nor did I find anything in the File.* commands.

( I know that I could travel through all open windows and compare paths..)


Norbert Vischer
--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

Re: isOpen("path") ?

dscho
Hi Norbert,

On Sat, 16 Mar 2013, Norbert Vischer wrote:

> Is there a simple way to check if a stored image is open?

Unfortunately, no simple way (the macro language is too simple for true
object-oriented programming and that's what you essentially require).

> For example,
>
>    isOpen("/Users/norbert/Desktop/blobs.gif")
>
> would be nice, but seems not to be supported, nor did I find anything in
> the File.* commands.
>
> ( I know that I could travel through all open windows and compare paths..)

That would work, of course, but it would be slow:

-- snip --
// This function detects path -> image-index pairs
// You can use List.get(path) to get the image-index
// and selectImage(index + 1) to make it the active image
function getOpenedPaths() {
        List.clear();
        count = nImages();
        for (i = 0; i < count; i++) {
                selectImage(1 + i);
                path = getInfo("image.directory") + getInfo("image.filename");
                List.set(path, i);
        }
}
-- snap --

You would use it that way:

-- snip --
getOpenedPaths();

path = "/path/to/my/file.tiff";

id = List.get(path);
if (id == "") {
        print("Not open: " + path);
} else {
        selectImage(1 + id);
}
-- snap --

This would be slow and you would want to make sure that you run this only
in batch mode.

Unfortunately, there are some obstacles if you want to accelerate it, e.g.
by going Javascript:

-- snip --
// This function detects path -> image-index pairs
// You can use List.get(path) to get the image-index
// and selectImage(index + 1) to make it the active image
function getOpenedPaths() {
        // we need to use a system property since returning values from
        // eval("script", script) is broken in ImageJ 1.47m
        unused = call("java.lang.System.setProperty", "hopefully.unused", "");

        script = 'importClass(Packages.ij.IJ);'
                + 'importClass(Packages.ij.WindowManager);'
                + ''
                + 'var result = [];'
                + 'var count = WindowManager.getImageCount();'
                + 'for (var i = 0; i < count; i++) {'
                + ' image = WindowManager.getImage(1 + i);'
                + ' info = image.getOriginalFileInfo();'
                + ' if (info != null) {'
                + ' result.push(info.directory + info.fileName + "=" + i);
                + ' }'
                + '}'
                + ''
                + 'System.setProperty("hopefully.unused", result.join("\\n"));';
        x = eval('script', script);
        List.setList(call("java.lang.System.getProperty", "hopefully.unused"));
}
-- snap --

Ciao,
Johannes

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

Re: isOpen("path") ?

dscho
Hi Wayne,

On Sat, 16 Mar 2013, Johannes Schindelin wrote:

> function getOpenedPaths() {
> // we need to use a system property since returning values from
> // eval("script", script) is broken in ImageJ 1.47m
> unused = call("java.lang.System.setProperty", "hopefully.unused", "");
> [...]

The problem is that even after the attempt to imitate the Fiji scripting
framework by introducing the PlugInInterpreter class,
Macro_Runner#runJavaScript(String, String) still returns always null,
never an evaluated value:

https://github.com/fiji/imagej1/blob/master/ij/plugin/Macro_Runner.java#L233

sets 's', but a couple of lines later, it still just returns null in every
case.

Can you please fix that bug?

Ciao,
Johannes

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

Re: isOpen("path") ?

dscho
Dear Wayne,

On Sat, 16 Mar 2013, Rasband, Wayne (NIH/NIMH) [E] wrote:

> Hi Johannes,
>
> On Mar 16, 2013, at 2:57 PM, Johannes Schindelin wrote:
>
> > Hi Wayne,
> >
> > On Sat, 16 Mar 2013, Johannes Schindelin wrote:
> >
> >> function getOpenedPaths() {
> >> // we need to use a system property since returning values from
> >> // eval("script", script) is broken in ImageJ 1.47m
> >> unused = call("java.lang.System.setProperty", "hopefully.unused", "");
> >> [...]
> >
> > The problem is that even after the attempt to imitate the Fiji
> > scripting framework by introducing the PlugInInterpreter class,
> > Macro_Runner#runJavaScript(String, String) still returns always null,
> > never an evaluated value:
> >
> > https://github.com/fiji/imagej1/blob/master/ij/plugin/Macro_Runner.java#L233
> >
> > sets 's', but a couple of lines later, it still just returns null in
> > every case.
> >
> > Can you please fix that bug?
>
> The PlugInInterpreter class is currently not used to run JavaScript
> scrips and Macro_Runner.runJavaScript() has always returned null.

That matches exactly what I reported ;-)

> How would you propose returning  a value from a JavaScript script? We
> can't use the return statement because it is only allowed in functions.
> The only thing I can think of is assigning the return value to a
> variable and then retrieving the value of that variable.

The trick is not to use a 'return' statement (because -- as you pointed
out correctly -- the top-level script is not a function), but an
unassigned expression:

        eval("script", "1;");

This patch (which you can conveniently get into your working directory by
calling "git pull git://github.com/dscho/imagej1 fix-js-return") makes
that work:

-- snip --
diff --git a/ij/plugin/Macro_Runner.java b/ij/plugin/Macro_Runner.java
index 257ac6d..254f7d6 100644
--- a/ij/plugin/Macro_Runner.java
+++ b/ij/plugin/Macro_Runner.java
@@ -236,7 +236,7 @@ private static String runScript(Object plugin, String script, String arg) {
  IJ.runPlugIn("Jython", script);
  }
  }
- return null;
+ return "" + js;
  }
 
  /** Runs a BeanShell script the on current thread. Uses the plugin at
diff --git a/plugins/JavaScriptEvaluator.source b/plugins/JavaScriptEvaluator.source
index f72064a..37341c5 100644
--- a/plugins/JavaScriptEvaluator.source
+++ b/plugins/JavaScriptEvaluator.source
@@ -13,6 +13,7 @@ import javax.script.*;
 public class JavaScriptEvaluator implements PlugIn, Runnable  {
  Thread thread;
  String script;
+ private Object result;
 
  // run script in separate thread
  public void run(String script) {
@@ -33,12 +34,13 @@ public class JavaScriptEvaluator implements PlugIn, Runnable  {
  }
 
  public void run() {
+ result = null;
  try {
  ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
  ScriptEngine engine = scriptEngineManager.getEngineByName("ECMAScript");
  if (engine == null)
  {IJ.error("Could not find JavaScript engine"); return;}
- engine.eval(script);
+ result = engine.eval(script);
  } catch(Throwable e) {
  String msg = e.getMessage();
  if (msg.startsWith("sun.org.mozilla.javascript.internal.EcmaError: "))
@@ -50,4 +52,8 @@ public class JavaScriptEvaluator implements PlugIn, Runnable  {
  }
  }
 
+ @Override
+ public String toString() {
+ return "" + result;
+ }
 }
-- snap --

> Passing of arguments to JavaScript scripts also needs to be fixed. How
> would you propose doing that?

I do not think that there is a lot to fix. Last time I tried (with Fiji's
scripting framework, which I would have been happy to contribute to ImageJ
1.x), using GenericDialog instances (and calling the scripts via run(...,
args);) worked just fine.

If you want a solution that is safe to execute in headless mode, and that
allows easily for adding new interpreters without having to reference
those interpreters in ImageJ 1.x' core explicitly, I am afraid that you
would have to either use ImageJ2's scripting framework or replicate the
complete functionality thereof. If you want to benefit from my work, I
would be delighted to discuss how to adjust it to be able to use it from
vanilla ImageJ 1.x.

Ciao,
Johannes

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

Re: isOpen("path") ?

vischer
Thanks Johannes for your contribution. My mail was more a suggestion to accept paths in isOpen(string), and I had solved my problem already somehow, but I tried your macro and it worked as expected.

However, there is a basic problem as ImageJ in my opinion has no straight-forward concept to identify images and paths. It automatically can create duplicates which is confusing.

In Image>Show Info>, "title" and the end of "path" do not match after "Rename" or after loading the same image a second time. In the latter case, ImageJ opens a duplicate with a new name ("clown-1.tif") but still maintains the old path ending with "clown.tif".

Assume another case where "clown.tif" is on the dock - ImageJ will behave different depending on whether the clown was there as minimized window, or as file associated to ImageJ. In the latter case, each click creates a new duplicate.

When ImageJ chooses a new name for a duplicate, this name may already be occupied by a different file in the same folder, although this is not likely. The danger of unwanted overwriting is "solved" by warning "File already exists" before each attempt to "Save". (I routinely confirm without thinking).

It would be nice if ImageJ would behave like other applications:

- If the user gives any type of "Open" command to a file which is already open, its window should be brought to the front, rather than being duplicated with a different name. If it was edited meanwhile, the user should be asked which version to use.

- If the user gives a "Save" command and the path is known, the old file should be overwritten without additional confirmation

But may be it is to late to change all this?

Norbert
--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

Re: isOpen("path") ?

dscho
In reply to this post by dscho
Dear Wayne,

On Mon, 18 Mar 2013, Rasband, Wayne (NIH/NIMH) [E] wrote:

> On Mar 17, 2013, at 11:00 AM, Johannes Schindelin wrote:
>
> > The trick is not to use a 'return' statement (because -- as you
> > pointed out correctly -- the top-level script is not a function), but
> > an unassigned expression:
> >
> > eval("script", "1;");
> >
> > This patch (which you can conveniently get into your working directory
> > by calling "git pull git://github.com/dscho/imagej1 fix-js-return")
> > makes that work:
>
> It does work and it is in today's ImageJ 1.47n daily build. Thanks for
> providing this solution.

You're welcome. Although I'd like to mention that it would have been
easier to simply pull than to reapply things by hand.

> >> Passing of arguments to JavaScript scripts also needs to be fixed.
> >> How would you propose doing that?
> >
> > I do not think that there is a lot to fix. Last time I tried (with
> > Fiji's scripting framework, which I would have been happy to
> > contribute to ImageJ 1.x), using GenericDialog instances (and calling
> > the scripts via run(..., args);) worked just fine.
>
> Sorry, I should have been more specific. I am trying to figure out how
> this method
>
>    public String runJavaScript(String script, String arg)
>
> in the Macro_Runner class should pass the string argument to the script.
> The only thing I can think of is to append a line of code something like
>
>     arg = "value of 'arg'";
>
> to the script before it is evaluated. The script could then retrieve the
> argument by accessing the 'arg' variable. That would work but it doesn't
> seem like a very elegant solution.

Well, when you call the script, you can prepend it with anything anyway.

However, if you use the Java scripting API (as we already do in ImageJ2's
scripting framework -- hence my offer to help you avoid reinventing the
wheel with ImageJ 1.x), you can call ScriptEngine#put(String, Object) to
set local variables:

        http://docs.oracle.com/javase/6/docs/api/javax/script/ScriptEngine.html#put%28java.lang.String,%20java.lang.Object%29

I can easily make a pull'able branch to implement that, but I have the
impression that you want to implement it yourself anyway. If you would
like me to provide an easy-to-integrate change, however, please just let
me know! I'll be more than happy to contribute it!

Ciao,
Johannes

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

Re: isOpen("path") ?

dscho
Dear Wayne,

On Wed, 20 Mar 2013, Johannes Schindelin wrote:

> http://docs.oracle.com/javase/6/docs/api/javax/script/ScriptEngine.html#put%28java.lang.String,%20java.lang.Object%29
>
> I can easily make a pull'able branch to implement that, but I have the
> impression that you want to implement it yourself anyway. If you would
> like me to provide an easy-to-integrate change, however, please just let
> me know! I'll be more than happy to contribute it!

I made the change, tested it, and you can easily pull it like this:

        git pull git://github.com/dscho/imagej1 javascript-arg

Ciao,
Johannes

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
| More
Print post
Permalink

Re: isOpen("path") ?

dscho
Hi Wayne,

On Thu, 21 Mar 2013, Rasband, Wayne (NIH/NIMH) [E] wrote:

> On Mar 20, 2013, at 1:45 PM, Johannes Schindelin wrote:
>
> > On Wed, 20 Mar 2013, Johannes Schindelin wrote:
> >
> >> http://docs.oracle.com/javase/6/docs/api/javax/script/ScriptEngine.html#put%28java.lang.String,%20java.lang.Object%29
> >>
> >> I can easily make a pull'able branch to implement that, but I have
> >> the impression that you want to implement it yourself anyway. If you
> >> would like me to provide an easy-to-integrate change, however, please
> >> just let me know! I'll be more than happy to contribute it!
> >
> > I made the change, tested it, and you can easily pull it like this:
> >
> > git pull git://github.com/dscho/imagej1 javascript-arg
>
> I decided to prepend a getArgument() function to the script in order to
> be consistent with the way arguments are passed to macros. This make it
> easier to document how the Macro_Runner.runMacroFile() method works:
>
>    /** Opens and runs the specified macro or script file on the current
>         thread. The file is assumed to be in the ImageJ/macros folder
>         unless 'name' is a full path. ".txt"  is added if 'name' does not
>         have an extension. The macro or script can use the getArgument()
>         function to retrieve the string argument.
>    */
>    public String runMacroFile(String name, String arg) {

Nice! It is even thread-safe (in contrast to the macro function, but then,
too many things in macros are thread-unsafe already to allow for
concurrent execution). At least if ScriptEngines are not reused (I vaguely
remember reading someething about this not being guaranteed, but in that
case, my put() approach would be thread-unsafe, too).

The only problem I see with the current getArgument approach is that it
does not adhere to Postel's law by leaving the arg unquoted.

Ciao,
Johannes

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html