Open xp1632 opened 9 months ago
plugin
?@Plugin
annotation@Plugin(type=Service.class)
public class MyService implements Service { }
Context
there're more than one match of plugin@Plugin
annotation@Plugin(priority=224)
public class SpecialService implements Service { }
Context
:Context
to ImageJ
, Context
is automatically created when the application starts up.Context
would cause problem as it will be another container than ImageJ
is using.Context
are provided automatically by the framework- Typically ImageJ plugin developers will be writing :
Service
and/or
Command
pluginsIf we would like to use another service or plugins in customized plugin:
we should ask our Context
for an instance instead of manually creating it. Because manually creating it would disconnect us from our application Context
Here's how we ask our Context
for LogService
:
@Plugin
public class MyPlugin {
// This @Parameter notation is 'asking' the Context
// for an instance of LogService.
@Parameter
private LogService logService;
public void log(String message) {
// Just use the LogService!
// There is no need to construct it, since the Context
// has already provided an appropriate instance.
logService.info(message);
}
}
@Parameter
annotation and desired typenew Myplugin()
we used doesn't work:In normal case, the way of using a method in Java or Groovy is to new a class
,
then call the method in the class
Context
:When MyPlugin
class in the above is manually constructed via new MyPlugin()
the LogService
parameter will be null
Automatic population only occurs if the plugin instance itself is retrieved via framework
When we need to manually construct a plugin instance, we need to reconnect to
current Context
via injection
mechanism:
public class MyService {
// This service will manually create plugin instances
// So, we need a reference to our containing Context
// Then we can use it to inject our plugins.
@Parameter
private Context context;
public void doStuff() {
// Manually create a plugin instance
// It is not connected to a Context yet
MyPlugin plugin = new MyPlugin();
// Inject the plugin instance with our Context,
// so the logService field of the plugin will be
// populated.
context.inject(plugin);
// Now that our plugin is injected, we can use
// it with the knowledge that its parameters
// have been populated
plugin.log("Success!");
}
}
MyPlugin
in current Context
, and you can seeLogService
we defined in MyPlugin
can be used in MyService
nowServices provide two important functions to the SciJava framework:
If we need a reusable Java method throughout the SciJava framework,
we could create a Service
to provide this functionality
Service
should be used to encapsulate the state.@Parameter
annotation instead of creating a new instance manually just like we said in here @Plugin
and @Parameter
because Op is also a plugin.// The @Plugin annotation is processed by the javac compiler,
// which is used to generate the metadata in class bytecode.
// Unfortunately, the Groovy compiler doesn't invoke the javac
// compiler, so we need to register the plugin manually!
narfInfo = new PluginInfo(Narf.class, Op.class)
ij.plugin().addPlugin(narfInfo)
narfInfo
after registration then we can execute our op:
// Execute our Op and get the result
result = ij.op().run("narf", "Put some trousers on")
The ij.plugin().addPlugin()
is from the PluginService in SciJava framework
Whereas Services provide internal functionality, Commands
are plugins to be executed one-off, typically interacting with users to achieve desired outcome
Commands
are created and executed on demand while Service
is instantiated when Context
startup
In Commands
, we often declare @Parameeters
that cannot be automatically by Context
, for example, file path
Command Execution and Parameter Acquisition
When a Command
is executed, it goes through pre-processing steps to populate
@Parameters
using associated Context
If any parameters are left unresolved and a UI is available, the framework will automatically build and display a dialog to get user input
Commands
can typically run headlessly
A common pattern in Command
development is to wrap Service
functionality.
For example,
To open an image from a path
Developers can directly use [DatasetIOService]
(https://github.com/scifio/scifio/blob/scifio-0.25.0/src/main/java/io/scif/services/DatasetIOService.java)
Users can get same functionality from menu via [OpenDataset command]
(https://github.com/imagej/imagej-plugins-commands/blob/imagej-plugins-commands-0.6.0/src/main/java/net/imagej/plugins/commands/io/OpenDataset.java), where the DatasetIOService is wrapped in the command
Looking for services in javadoc
- Main plugin types:
Ops: reusable image processing algorithms
Image formats: support new types of images in ImageJ
1. plugin template for imageJ2 : https://github.com/imagej/example-imagej2-command
we clone this repo and open it with VS code that has maven/java extensions installed
GaussFilter.java
is where we write our plugin functional content
pom.xml
is where we write the dependencies, groupId, names, authors so the maven could manage the import for usGaussFilter.java
Import Part
import
part:net.imagej
and net.imglib2
are typical packages for ImageJ2ij.IJ
and ij.ImageJ
, ij.xx
are typical packages for ImageJ1
@Plugin @Parameter Annotation part
HelloWorld.java
Plugin@Plugin
annotation lets ImageJ know that this is a plugin
Command
Plugins are the most common one which take inputs and produce outputs, our plugin HelloWorld
implements based on Command
class
_
@Parameter
annotation lets ImageJ know the inputs of this plugin, in HelloWorld
, we only used string parameters.
If we want to use more complex method such as the Services
in Scijava framework, we can also annotate it with @Parameter
, the ImageJ context would automatically create an instance of that Service
for us. I'll show this in the next example GaussianFilter
Plugin.
_
The run()
method of every Command
, is the entry point for ImageJ, which is what is called when the user clicks the menu entry of this plugin.
main()
for fast testing
main()
method, we create an ImageJ content and call the plugin, so we could fast test it in our IDE.the complexity of GaussianFilter
plugin is that, it uses other Services
in Scijava framework:
As we mentioned here, we should not manually create a Service
, we should annotate it with @Parameter
and the ImageJ context would create the instance for us.
As in the picture, the UIService
and OpService
are annotated with @Parameter
,
run()
method- In run()
method,
RandomAccessibleInterval(which is a image type in ImageJ2)
results of filtered images
opService
we declared earlieruiService
we declared earlier- In main()
method
Run Java
, then you can check the performance of plugin in imageJ context ij.command().run(GaussFiltering.class, true);
To build a Maven project into a JAR file in Visual Studio Code, you can use the integrated terminal and the Maven command line tool. Here are the steps:
Open the integrated terminal in Visual Studio Code. You can do this by going to the View
menu and selecting Terminal
, or by pressing `Ctrl+`` (backtick).
Navigate to the root directory of your Maven project (the directory that contains the pom.xml
file). You can do this with the cd command. For example, if your project is in a directory called my-project, you would type cd my-project.
Run the mvn package
command. This command will compile your code, run any tests, and package the compiled code into a JAR file. The JAR file will be created in the target directory of your project.