我正在研究将应用程序从Swing传递到JavaFx 8是否合理,我需要帮助。该应用程序实时可视化图像,基本上我用一定频率更新图像,例如1秒。图像尺寸为28k x 4k;当我使用JavaFx imageView时,与Swing相比,性能很差。(fps很低,大约1-2,应用程序滞后)。我是通过以下方式完成的:
animation = new Timeline();
animation.getKeyFrames().add(new KeyFrame(Duration.millis(1000), new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
for (int count = 0; count < 1; count++) {
if (indicator)
imageView.setImage(writableImage);
else
imageView.setImage(image1);
indicator = !indicator;
}
}
}));
animation.setCycleCount(Animation.INDEFINITE);
所以我尝试使用JavaFx画布:
imageCanvas.setHeight(image1.getHeight());
imageCanvas.setWidth(image1.getWidth());
imageCanvas.getGraphicsContext2D().drawImage(image1, 0, 0);
当我尝试时,我收到以下错误。
java.lang.NullPointerException
at com.sun.prism.impl.BaseGraphics.drawTexture(BaseGraphics.java:400)
at com.sun.prism.impl.ps.BaseShaderGraphics.drawTexture(BaseShaderGraphics.java:139)
at com.sun.javafx.sg.prism.NGCanvas.handleRenderOp(NGCanvas.java:1336)
at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:1086)
at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:595)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2308)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2202)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2228)
at com.sun.javafx.sg.prism.CacheFilter.impl_renderNodeToCache(CacheFilter.java:663)
at com.sun.javafx.sg.prism.CacheFilter.render(CacheFilter.java:567)
at com.sun.javafx.sg.prism.NGNode.renderCached(NGNode.java:2372)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2058)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2308)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2202)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2228)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2061)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:235)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:576)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2067)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1959)
at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:474)
at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:320)
at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:91)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
at java.lang.Thread.run(Thread.java:745)
问题是由图像的尺寸引起的,因为它适用于较小的图像。首先,我不明白为什么与Swing相比,imageView的性能差得多? (在摇摆中,我使用扩展JPanel和paintComponent方法的面板。)
其次,JavaFx中画布的大小是否存在某种限制?
提前谢谢你。
答案 0 :(得分:3)
为什么您的JavaFX应用程序不起作用
28k x 4k是绝对庞大的图像,JavaFX 8不直接支持硬件管道。我不知道这个限制是否在任何地方正式记录。
请参阅:Maximum dimensions of canvas in JavaFX。
默认的JavaFX渲染管道将尝试将图像(和画布)绘制到视频卡上的纹理上(用于硬件加速合成支持)。视频卡的大小受限于它们所支持的纹理,通常它是2的幂,例如,8192 x 8192. JavaFX(至少在我以前的版本中使用过),如果你尝试渲染一个,它只会抛出异常图像大于底层视频硬件支持的最大纹理大小。
潜在的解决方法
要解决JavaFX中的纹理大小限制,请处理图像的传入数据并将其加载到7个4k x 4k图像中(使用带有像素编写器的可写图像)。执行此操作时,请确保输入数据在适当的PixelFormat中进行编码,例如: ByteBgraPreInstance
,otherwise data conversion will be required可能会极大地影响您的应用程序的性能。
JavaFX有一些未记录的开关可以禁用硬件渲染,而是使用软件渲染管道。这些开关可能会或可能不会允许您的应用程序使用大图像大小而不实现上述切片算法,但是,它可能更适合您的应用程序整体,保持硬件加速图形管道启用并编写您的应用程序在其中工作该管道的局限性(通过实现大图像支持的自定义平铺算法)。
效果方面
对于JavaFX程序与Swing程序的性能差异,如果没有两个程序的源代码就不可能进行分析(即使提供了源代码也可能很难)。所以我不会就你问题的这个方面做进一步的评论。
Canvas是一个比ImageView更复杂的控件,使用Canvas完成此任务不太可能比使用ImageView提供更好的性能。