I'm capturing images from a scanner device with java. The input format ist PGM or TIFF. I have to show up live results in the user interface. Actually I'm using ImageJ to read the source input stream as tiff, because ImageJ can also handle incomplete streams. After that the ImagePlus
object is converted into a BufferedImage
and finally into a JavaFX Image
.
ImagePlus imagePlus = new Opener().openTiff(inputStream, "");
BufferedImage bufferedImage = imagePlus.getBufferedImage();
Image image = SwingFXUtils.toFXImage(bufferedImage, null);
This is very slow. I need a faster way to create the JavaFX Image
from the PGM or TIFF stream. It seems that JavaFX has actually no support for this formats and I don't found a usefull library.
Any idea?
Edit #1
I've decided to optimze the image capturing in two steps. At first I need a better state control when updating the image in the ui. This is actually done and works fine. Now update requests are dropped, when the conversion thread is busy. The second step is to use a self implemented pnm reader (based on the suggested implementation) and update the image in my model incrementally... until the scan process is complete. This should reduce the required recources when loading an image from the device. I need to change some parts of my architecture to make this happen.
Thanks @ all for comments.
btw: java 8 lambdas are great :)
Edit #2
My plan doesn't work, because of JavaFX's thread test :(
Currently I have a WritableImage
in my backend wich should be filled step by step with data. This image instance is set to an ObjectProperty
that is finally bound to the ImageView
. Since the WritableImage
is connected to the ImageView
it's impossible to fill it with data by using a PixelWriter
. This causes an exception.
java.lang.IllegalStateException: Not on FX application thread; currentThread = pool-2-thread-1
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:210) ~[jfxrt.jar:na]
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:393) ~[jfxrt.jar:na]
at javafx.scene.Scene.addToDirtyList(Scene.java:529) ~[jfxrt.jar:na]
at javafx.scene.Node.addToSceneDirtyList(Node.java:417) ~[jfxrt.jar:na]
at javafx.scene.Node.impl_markDirty(Node.java:408) ~[jfxrt.jar:na]
at javafx.scene.Node.transformedBoundsChanged(Node.java:3789) ~[jfxrt.jar:na]
at javafx.scene.Node.impl_geomChanged(Node.java:3753) ~[jfxrt.jar:na]
at javafx.scene.image.ImageView.access$700(ImageView.java:141) ~[jfxrt.jar:na]
at javafx.scene.image.ImageView$3.invalidated(ImageView.java:285) ~[jfxrt.jar:na]
at javafx.beans.WeakInvalidationListener.invalidated(WeakInvalidationListener.java:83) ~[jfxrt.jar:na]
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:135) ~[jfxrt.jar:na]
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80) ~[jfxrt.jar:na]
at javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:74) ~[jfxrt.jar:na]
at javafx.scene.image.Image$ObjectPropertyImpl.fireValueChangedEvent(Image.java:568) ~[jfxrt.jar:na]
at javafx.scene.image.Image.pixelsDirty(Image.java:542) ~[jfxrt.jar:na]
at javafx.scene.image.WritableImage$2.setArgb(WritableImage.java:170) ~[jfxrt.jar:na]
at javafx.scene.image.WritableImage$2.setColor(WritableImage.java:179) ~[jfxrt.jar:na]
My workaround is to create a copy of the image, but I don't like this solution. Maybe it's possible to prevent the automatic change notification and do this manually?