Posted by
dscho on
Jul 01, 2014; 10:22pm
URL: http://imagej.273.s1.nabble.com/Recommendations-for-Creating-a-Writer-Plugin-in-ImageJ1-and-2-tp5008522p5008524.html
Hi Alan,
On Tue, 1 Jul 2014, alanb wrote:
> I am looking for some recommendations. I have been asked to create a
> file writer plugin for ImageJ that can write a proprietary raw data
> image file format. (This is not because we think this format is good--it
> is not--but it is for customer that wants to manipulate intermediate
> data and then run it through the rest of our software system.)
>
> Our company's service personnel use ImageJ in many locations without
> internet access and currently have ImageJ1 (varied versions) deployed on
> our machines. No one yet uses ImageJ2 (or Fiji) but I want to consider
> my options.
>
> Ideally, I'd like to write something that works well as an ImageJ1
> writer plugin but also could be used as an ImageJ2 writer (and reader).
> I already have a crufty ImageJ1 reader for this format that I don't plan
> on touching much at this time unless there are enhancements that come
> for little cost/time.
>
> As far as I can tell, the recommended method of creating an ImageJ1
> writer is to make a PluginFilter that writes the file and then put it in
> a jar with a plugins.config file with contents such as:
> File>Save As, "Format Name...", Format_Writer
Correct, maybe two more suggestions:
- the PlugInFilter (careful about the upper-case "i") takes an ImagePlus
and a String in its setup() method, but only an ImageProcessor in the
run() method. If you want to support writing stacks, you definitely want
to store the ImagePlus in a field and not use the ImageProcessor (which
is *just* the current slice). Also, do not return DOES_STACKS in that
case: that will trigger the run() method to be called *for every* slice.
- ImageJ 1.x supports macros by reusing the label of the menu item for the
run() call. That means that no two menu items, no matter whether they
live in the same menu or not, can share the same label. Since it is
common to desire the same name for reader and writer, the convention is
to append a single space for the writer. It is a bit clumsy, but that's
how things work.
> From what I read on forums ([1],[2]) and on
>
https://github.com/scifio/scifio/wiki/Adding-support-for-an-image-format,
> the recommended method of creating an ImageJ2 file reader or writer plugin
> is to make a SCIFIO plugin that implements AbstractFormat and put the
> resulting jar somewhere where it is automatically found by ImageJ2 (I'm not
> sure where that is -- perhaps just the ).
Exactly: you just have to put the .jar file onto the class path. The
convention is to put plugins into the plugins/ directory, but even jars/
will work.
The details why this works are quite cunning, if I may say so: we are
using a quite powerful framework based on annotation processing. That
means that the annotations (these funky "@Plugin(type = Format.class)"
thingies) are not only attached to the class definition, but can be
inspected *at compile time*, by a so-called annotation processor. One such
annotation processor indexes the just-compiled annotations and writes out
the index into META-INF/ which is included in the .jar file.
The bottom line for the developer is that they do not need to conform to
some file name convention, do not need to put the files into the exact
right spot, do not need a plugins.config file. The .jar file just needs to
be on the class path and that's it.
There is another, quite important benefit to this framework: new plugin
types can be defined very easily. Just define an interface that extends
the (empty) SciJavaPlugin interface. That's it. All plugins need to do is
to implement that interface and annotate the class with @Plugin(type =
MyCoolNewPlugin.class). To consume those plugins, one needs only ask the
PluginService associated with the current Context. But I digress... and I
should find the time to write a blog post about this.
> Specific Questions:
> 1. Is it unreasonable to share writer/reader code between ImageJ1 and
> ImageJ2?
It makes a ton of sense, if you ask me. In particular, I would try to
avoid conflating the logic to write the image with the specifics of the
plugins as much as possible.
> 2. Where do I put writer/reader jars for ImageJ2? Just in the normal
> /jars folder?
Well, I would put it into the plugins/ directory.
The jars/ directory was only introduced by Fiji (and not really picked up
by ImageJ 1.x until much much later) to avoid problems with the naming
conventions: in the early days, we shipped the jai_core.jar file as
downloaded from the website. You will note the underscore which ImageJ 1.x
mistook as an indicator that this .jar file is a plugin. Worse: the
absence of a plugins.config file was taken to suggest that the contents of
the .jar file should be inspected for .class files having an underscore in
their file name, and sure enough, there was one. Actually, four. They were
faithfully added into the Plugins>com>sun>media>jai>rmi menu.
Unfortunately, we could not come up with a better solution than to add
*another* directory.
Traditionally, the only reason to have a hard-coded directory for the
plugins is to be able to throw away the class loader that loaded the
plugin classes and make a new one (because class loaders cannot unload
classes by default), i.e. the architecture was influenced by an
implementation detail.
So in the future, I'd really rather have the plugins anywhere in the class
path, for tradition's sake probably in plugins/.
Ciao,
Dscho
--
ImageJ mailing list:
http://imagej.nih.gov/ij/list.html