ImageJ plugin not working under Fiji

I saw the Import -> Oranthc under ImageJ and verified that it works there.
I would like to use it under Fiji and there it fails.
Looking at the source the call is made from

  public BufferedImage ReadImage(String uri) throws IOException
  {
    // Ask the download of "image/png", otherwise an "image/jpeg" is negociated
    return ImageIO.read(OpenStream(uri, "image/png"));
  }

where uri works through
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream

In ImageJ this calls to

package javax.imageio;

    public static BufferedImage read(InputStream input) throws IOException {
        if (input == null) {
            throw new IllegalArgumentException("input == null!");
        }

        ImageInputStream stream = createImageInputStream(input);
        BufferedImage bi = read(stream);
        if (bi == null) {
            stream.close();
        }
        return bi;
    }

All goes through smoothly. Not so under Fiji. Instead an exception is thrown at

Exception in thread "AWT-EventQueue-0" java.lang.NoSuchMethodError: com.sun.media.imageioimpl.common.PackageUtil.isCodecLibAvailable()Z
  at com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReaderSpi.onRegistration(CLibJPEGImageReaderSpi.java:109)
  at javax.imageio.spi.SubRegistry.registerServiceProvider(ServiceRegistry.java:726)
  at javax.imageio.spi.ServiceRegistry.registerServiceProvider(ServiceRegistry.java:307)
  at javax.imageio.spi.IIORegistry.registerApplicationClasspathSpis(IIORegistry.java:211)
  at javax.imageio.spi.IIORegistry.<init>(IIORegistry.java:138)
  at javax.imageio.spi.IIORegistry.getDefaultInstance(IIORegistry.java:159)
  at javax.imageio.ImageIO.<clinit>(ImageIO.java:66)
  at com.orthancserver.OrthancConnection.ReadImage(OrthancConnection.java:197)

At line 197 (above) is the ReadImage call. It goes off the ImageIO.<clinit> and from there to never, never land.

From the javax documentation

Returns a BufferedImage as the result of decoding a supplied URL with an ImageReader chosen automatically from among those currently registered. An InputStream is obtained from the URL, which is wrapped in an ImageInputStream. If no registered ImageReader claims to be able to read the resulting stream, null is returned.

I'm not at all sure if I'm on the right track but could it be that
OpenStream(uri, "image/png")
is somehow not defined for image/png in Fiji, so that <clinit> doesn't know where to go?

I would very much like to use the plugin with Fiji if it is possible to do so.

Thanks,
Ilan

Hello,

I saw the Import → Oranthc under ImageJ and verified that it works there.
I would like to use it under Fiji and there it fails.

Thanks for your feedback and for your interest in interfacing Orthanc with Fiji! Unfortunately, as far as I’m concerned, I have not enough time to dig by myself into the internals of Fiji.

Have you tried getting in touch with the Fiji community? As 99% of the work is already done in the Orthanc-ImageJ interface, I am pretty sure some Fiji developer would be happy to solve this issue.

Regards,
Sébastien-

Hi Sebastien,
I'm not sure how much interest there is in the Fiji community to solve the problem. I understand that you wrote this software, so I would be willing to try and take it on with some help on your part.

What I'm guessing is the problem is with the Orthanc server in that something there knows about ImageJ, but not about Fiji (where Fiji is really just ImageJ). It is strange that it should not work. Perhaps some internal name is slightly different so that it doesn't recognize it.

Some sort of ImageReader has to be registered, presumably inside Orthanc, and it is registered for ImageJ but not for the Fiji version of ImageJ. Do you remember where the readers are registered? If I could get a break point at the proper place I might be able to figure out what it is lacking.

Thanks,
Ilan

What I’m guessing is the problem is with the Orthanc server in that something there knows about ImageJ, but not about Fiji (where Fiji is really just ImageJ). It is strange that it should not work. Perhaps some internal name is slightly different so that it doesn’t recognize it.

According to your log, your issue occurs in the “OrthancConnection.ReadImage()” function:
https://goo.gl/XIZ2p4

At this point of the source code, the Orthanc-ImageJ interface uses the Java standard library “ImageIO” to decode a grayscale PNG image encoded in 16bpp that was downloaded using the REST API of Orthanc. I suspect Fiji’s JRE does not natively support the decoding of such PNG 16bpp images.

The solution might be to replace “ImageIO” with a standalone library such as pngj:

Some sort of ImageReader has to be registered, presumably inside Orthanc, and it is registered for ImageJ but not for the Fiji version of ImageJ. Do you remember where the readers are registered?

The Orthanc-ImageJ interface never registers any ImageReader: All is transparently done by ImageJ.

I hope this might provide you with a direction about where to start the investigation…

HTH,
Sébastien-

Hi Sebastien,
Both ImageJ and Fiji use a very recent JRE: java 1.8.0_111 [64 bit], on my machine. The URL is /instances/c17b...../preview, where the c17b is a long hex string. I looked around for where this object could be located if it were already downloaded. The only place I found was clearly wrong:

netbeans-8.1/nb/config/GlassFishEE6/instances/glassfish_autoregistered_instance

which I guessed meant the link was not yet actually downloaded.

You are correct that the problem occurs in OrthancConnection.ReadImage function. My breakpoint is placed at

  public BufferedImage ReadImage(String uri) throws IOException
  {
    // Ask the download of "image/png", otherwise an "image/jpeg" is negociated
---> return ImageIO.read(OpenStream(uri, "image/png"));
  }

Under ImageJ if I step into the ImageIO.read, it goes to the ImageIO read function, which is what I expect. Under Fiji, using the same java 1.8 it goes to

EventDispatchThread.java
    void pumpOneEventForFilters(int id) {
        AWTEvent event = null;
        boolean eventOK = false;
        try {
            EventQueue eq = null;
            EventQueueDelegate.Delegate delegate = null;
            do {
                // EventQueue may change during the dispatching
                eq = getEventQueue();
                delegate = EventQueueDelegate.getDelegate();

                if (delegate != null && id == ANY_EVENT) {
                    event = delegate.getNextEvent(eq);
                } else {
                    event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id);
                }

                eventOK = true;
                synchronized (eventFilters) {
                    for (int i = eventFilters.size() - 1; i >= 0; i--) {
                        EventFilter f = eventFilters.get(i);
                        EventFilter.FilterAction accept = f.acceptEvent(event);
                        if (accept == EventFilter.FilterAction.REJECT) {
                            eventOK = false;
                            break;
                        } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) {
                            break;
                        }
                    }
                }
                eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
                if (!eventOK) {
                    event.consume();
                }
            }
            while (eventOK == false);

            if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
                eventLog.finest("Dispatching: " + event);
            }

            Object handle = null;
            if (delegate != null) {
                handle = delegate.beforeDispatch(event);
            }
---> eq.dispatchEvent(event);
            if (delegate != null) {
                delegate.afterDispatch(event, handle);
            }
        }
        catch (ThreadDeath death) {
            doDispatch = false;
            throw death;
        }
        catch (InterruptedException interruptedException) {
            doDispatch = false; // AppContext.dispose() interrupts all
                                // Threads in the AppContext
        }
        catch (Throwable e) {
            processException(e);
        }
    }

where it seems to be pumping for a registered object. This is in line with what the documentation says about registered image readers.

The fact that you say you don't register anything is very bad. It means we have nothing to go on. Who interprets /instances/c17b...../preview?

BTW the link you suggested is for Android. Java itself should have no problem with png files. I am really stuck for what could be the next step. What I hoped could be fairly easy is turning into a nightmare.

Best regards,
Ilan

Hi Sebastien,
Salim has a much better memory than I do, and he remembered some previous problems we had with decompressing jpeg 2000 images.
There is a bioformats section in Fiji and they have 2 jai_imageio...jar files.
Apparently these files replace the Java default imagio files.

In any case, I just removed them from Fiji and Orthanc started to work as expected. I'm sure bio formats won't work but at least we now know where the problem is.

Thanks for your help,
Ilan

Hi Ilan,

Both ImageJ and Fiji use a very recent JRE: java 1.8.0_111 [64 bit], on my machine. The URL is /instances/c17b…/preview, where the c17b is a long hex string.

“/instances/{id}/preview” is an endpoint in the REST API of Orthanc that generates a PNG 8bpp image (either grayscale or color) from the DICOM instance whose Orthanc identifier is “{id}”. You can find more information in the Orthanc Book:
http://book.orthanc-server.com/users/rest.html#downloading-images

So, the issue is not in the PNG 16bpp decoding as I previously thought, but even in the basic decoding of PNG 8bpp image that is supported by any JRE.

Under ImageJ if I step into the ImageIO.read, it goes to the ImageIO read function, which is what I expect. Under Fiji, using the same java 1.8 it goes to

EventDispatchThread.java […] where it seems to be pumping for a registered object. This is in line with what the documentation says about registered image readers.

As a consequence, Fiji and ImageJ do not behave similarly. This is really a question you should ask to the Fiji community: “How to register the image decoder for PNG 8bpp and 16bpp images?”

The fact that you say you don’t register anything is very bad. It means we have nothing to go on. Who interprets /instances/c17b…/preview?

It is up to the HTTP client to decode this image (that was encoded by the Orthanc server). The HTTP client might be your Web browser (as in Orthanc Explorer), or the JRE (as in the Orthanc-ImageJ interface).

BTW the link you suggested is for Android. Java itself should have no problem with png files.

PNGJ is a pure native Java library. As such, this library will work on any JRE (including that of Fiji).

HTH,
Sébastien-

Mid-air collision :wink:

This is great to know that Orthanc-ImageJ actually works with Fiji. Thanks for the feedback.

On a side note, if you want to read DICOM JPEG2k from Fiji using the Orthanc-ImageJ interface, you will have to install the official Web viewer plugin into Orthanc:
http://www.orthanc-server.com/static.php?page=web-viewer

Regards,
Sébastien-