imagej / pyimagej

Use ImageJ from Python
https://pyimagej.readthedocs.io/
Other
473 stars 82 forks source link

Cannot invoke ImageJ1 plugins with Maven-based initialization #36

Closed ctrueden closed 4 years ago

ctrueden commented 5 years ago

As noted in https://github.com/imagej/pyimagej/issues/35#issuecomment-493019994, if you initialize an ImageJ gateway that includes ImageJ1 plugin artifacts on the classpath, for example a standard Fiji installation as follows...

ij = imagej.init('sc.fiji:fiji:2.0.0-pre-10')

...then it is not possible to invoke the ImageJ1 plugins via ij.py.run_plugin. You'll see an error similar to:

Unrecognized command: "Grid/Collection stitching"

This is because ImageJ1 needs a system property plugins.dir set to a local file path containing all the plugin JARs. ImageJ1 cannot run plugins present on the classpath but not present in a single folder pointed at by this system property.

It is likely possible to work around this limitation. For example, one solution might be to use the ij1.plugin.dirs property, added by ImageJ2's ij1-patcher integration layer, setting it to match directories above all entries of java.class.path, so that all JARs present on the classpath are also available to ImageJ1. But I have not tried doing this yet. So I do not know if it work, and if so, what the performance implications would be.

ctrueden commented 5 years ago

I found a workaround:

Hack to add all plugins from the classpath to ImageJ1 ```python import re from jnius import autoclass Menus = autoclass('ij.Menus') BufferedReader = autoclass('java.io.BufferedReader') InputStreamReader = autoclass('java.io.InputStreamReader') Thread = autoclass('java.lang.Thread') commands = Menus.getCommands() print('BEFORE: {} IJ1 commands'.format(commands.size())) pattern = re.compile('[^"]*"([^"]*)",\s*([^\s]*)') cl = Thread.currentThread().getContextClassLoader() pluginsConfigs = cl.getResources('plugins.config') while pluginsConfigs.hasMoreElements(): pluginsConfig = pluginsConfigs.nextElement() r = BufferedReader(InputStreamReader(pluginsConfig.openStream())) while True: line = r.readLine() if line is None: break match = pattern.match(line) if match is None: continue label = match.group(1) plugin = match.group(2) commands.put(label, plugin) r.close() print('AFTER: {} IJ1 commands'.format(commands.size())) ```

I will add this functionality to imagej-legacy soon, obviating the need for this hack on the Python side. Once that is in place, this issue will be able to close.

ctrueden commented 4 years ago

With imagej/imagej-legacy#228, ImageJ 1.x plugins can now be used whenever they are available to the class loader. So it now works to initialize an ImageJ using a Maven coordinate and then invoke ImageJ 1.x plugins, even without plugins.dir being set.

There are still plenty of issues with running many of the ImageJ1 plugins in headless mode, but at least the ImageJ1 execution mechanism fundamentally knows about them now.