如何解决无法识别的图像加载器:JavaFX中的null?

时间:2018-03-13 16:10:07

标签: java javafx

我的应用程序,使用JavaFX用Java 8编写,截取屏幕截图,或者更确切地说是快照,两次它生成了这个错误:

java.lang.IllegalArgumentException: Unrecognized image loader: null
    at javafx.scene.image.WritableImage.loadTkImage(WritableImage.java:240)
    at javafx.scene.image.WritableImage.access$000(WritableImage.java:46)
    at javafx.scene.image.WritableImage$1.loadTkImage(WritableImage.java:51)
    at javafx.scene.Scene.doSnapshot(Scene.java:1236)
    at javafx.scene.Node.doSnapshot(Node.java:1864)
    at javafx.scene.Node.snapshot(Node.java:1942)

到目前为止,在我的应用程序中,我无法重现它。搜索这个问题我发现了这个:

https://bugs.openjdk.java.net/browse/JDK-8116783

指向:

https://bugs.openjdk.java.net/browse/JDK-8088198

它似乎是JavaFX中的一个漏洞:“如果维度大于最大纹理大小,则会从快照抛出异常”。

该错误的描述表明偶尔会发生这种情况。有人知道如果捕获异常并重试将是一个好方法或解决方法吗?

更新:当我尝试通过使屏幕截图非常大来重现此错误时,我得到了完全不同的错误:

java.lang.NullPointerException
    at com.sun.prism.impl.ps.BaseShaderContext.initLCDBuffer(BaseShaderContext.java:703)
    at com.sun.prism.impl.ps.BaseShaderContext.validateLCDBuffer(BaseShaderContext.java:725)
    at com.sun.prism.impl.ps.BaseShaderGraphics.initLCDSampleRT(BaseShaderGraphics.java:1925)
    at com.sun.prism.impl.ps.BaseShaderGraphics.drawString(BaseShaderGraphics.java:2059)
    at com.sun.javafx.webkit.prism.WCGraphicsPrismContext$10.doPaint(WCGraphicsPrismContext.java:936)
    at com.sun.javafx.webkit.prism.WCGraphicsPrismContext$Composite.paint(WCGraphicsPrismContext.java:1500)
    at com.sun.javafx.webkit.prism.WCGraphicsPrismContext$Composite.paint(WCGraphicsPrismContext.java:1485)
    at com.sun.javafx.webkit.prism.WCGraphicsPrismContext.drawString(WCGraphicsPrismContext.java:948)
    at com.sun.webkit.graphics.GraphicsDecoder.decode(GraphicsDecoder.java:299)
    at com.sun.webkit.graphics.WCRenderQueue.decode(WCRenderQueue.java:92)
    at com.sun.webkit.WebPage.paint2GC(WebPage.java:734)
    at com.sun.webkit.WebPage.paint(WebPage.java:701)
    at com.sun.javafx.sg.prism.web.NGWebView.renderContent(NGWebView.java:96)
    at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2053)
    at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1945)
    at com.sun.javafx.tk.quantum.QuantumToolkit$5.draw(QuantumToolkit.java:1393)
    at com.sun.javafx.tk.quantum.QuantumToolkit$5.run(QuantumToolkit.java:1429)
    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:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
    at java.lang.Thread.run(Thread.java:748)

它同样是一个没有调用的线程触及我的代码。

3 个答案:

答案 0 :(得分:0)

它也发生在我身上......

如果快照最终变大,就会发生这种情况。

我能够通过在SnapshotParameters中添加一个比例来解决这个问题。一旦将手放在图像上,就可以做任何你想做的事情,包括恢复尺寸。

答案 1 :(得分:0)

TL; DR:

  • 即使使用Oracle JVM,也请参见:https://wiki.openjdk.java.net/pages/viewpage.action?pageId=20415996
  • 使用function theYears() { "use strict"; var firstInput = parseInt(document.getElementById("firstInput").value), secondInput = parseInt(secondInput = document.getElementById("secondInput").value), myDiv = '', myResult = document.getElementById("result"); var years; myDiv = "<select>"; for (years = firstInput; years <= secondInput; years += 1) { myDiv += '<option>' + years + '</option>'; } myDiv += "</select>"; myResult.innerHTML = myDiv; }检查您的最大vram限制并查看您实际消耗了多少vram
  • <input type="text" id="firstInput"> <input type="text" id="secondInput"> <input type="button" id="excute" value="Enter" onclick="theYears();"> <div id="result"></div>设置为较低的值可能有助于重现该问题
  • -Dprism.poolstats=true -Dprism.verbose=true设置为更高的值可能有助于解决问题

我的案子(针对任何有兴趣的人)

如上面链接中所建议,我使用了-Dprism.maxvram=xxxxM,发现maxvram足够高。无论如何,可以肯定的是,我添加了-Dprism.maxvram=xxxxM,但没有帮助。有足够的内存,但分配失败,并出现以下错误:

-Dprism.poolstats=true -Dprism.verbose=true

很明显,即使限制足够高,JVM也无法分配足够的内存。搜索-Dprism.maxvram=1024M -Dprism.targetvram=512M发现这实际上是Windows错误(https://docs.microsoft.com/en-us/windows/desktop/seccrypto/common-hresult-values):

D3D Vram Pool: 66.929.834 used (12,5%), 81.273.002 target (15,1%), 536.870.912 max
36 total resources being managed
average resource age is 12,6 frames
0 resources at maximum supported age (0,0%)
5 resources marked permanent (13,9%)
0 resources have had mismatched locks (0,0%)
0 resources locked (0,0%)
31 resources contain interesting data (86,1%)
0 resources disappeared (0,0%)

Growing pool D3D Vram Pool target to 116.658.814
Growing pool D3D Vram Pool target to 131.338.878
Growing pool D3D Vram Pool target to 159.043.730
D3D hresult failed :D3D_ERROR ffffffff8007000e
java.lang.Exception: Stack trace
        at com.sun.prism.d3d.D3DContext.validate(D3DContext.java:133)
        at com.sun.prism.d3d.D3DContext.validatePresent(D3DContext.java:183)
        at com.sun.prism.d3d.D3DRTTexture.readPixels(D3DRTTexture.java:116)
        at com.sun.prism.d3d.D3DRTTexture.readPixels(D3DRTTexture.java:90)
        at com.sun.javafx.tk.quantum.QuantumToolkit$5.run(QuantumToolkit.java:1437)
        at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
        at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
        at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
        at java.lang.Thread.run(Unknown Source)
D3D Vram Pool: 109.314.750 used (20,4%), 159.043.730 target (29,6%), 536.870.912 max
37 total resources being managed
average resource age is 13,1 frames
0 resources at maximum supported age (0,0%)
5 resources marked permanent (13,5%)
0 resources have had mismatched locks (0,0%)
0 resources locked (0,0%)
32 resources contain interesting data (86,5%)
0 resources disappeared (0,0%)

2018-07-17 18:05:09 [JavaFX Application Thread] de.apris3.client.ErrorHandler.handle()
   ERROR: : java.lang.IllegalArgumentException: Unrecognized image loader: null
        at javafx.scene.image.WritableImage.loadTkImage(WritableImage.java:240)
        at javafx.scene.image.WritableImage.access$000(WritableImage.java:46)
        at javafx.scene.image.WritableImage$1.loadTkImage(WritableImage.java:51)
        at javafx.scene.Scene.doSnapshot(Scene.java:1236)
        at javafx.scene.Node.doSnapshot(Node.java:1864)
        at javafx.scene.Node.snapshot(Node.java:1942)
        ...
D3D Vram Pool: 112.230.142 used (20,9%), 159.043.730 target (29,6%), 536.870.912 max
40 total resources being managed
average resource age is 13,0 frames
0 resources at maximum supported age (0,0%)
5 resources marked permanent (12,5%)
0 resources have had mismatched locks (0,0%)
0 resources locked (0,0%)
35 resources contain interesting data (87,5%)
0 resources disappeared (0,0%)

最后,在检查了设备管理器之后,事实证明客户端已安装了新的图形卡,并且Windows Update更新了驱动程序。

答案 2 :(得分:0)

尝试从大节点制作快照时遇到了相同的问题。 就我而言,缩放是不可能的,因为我需要高分辨率的图像。 为了解决该问题,我从节点的各个子节制作了多个快照,然后将它们快照在一起。

这是我写的函数:

private void exportPng(final Node node, final String filePath) {

    final int w = (int) node.getLayoutBounds().getWidth();
    final int h = (int) node.getLayoutBounds().getHeight();
    final WritableImage full = new WritableImage(w, h);

    // defines the number of tiles to export (use higher value for bigger resolution)
    final int size = 2; 
    final int tileWidth = w / size;
    final int tileHeight = h / size;

    System.out.println("Exporting node (building " + (size * size) + " tiles)");

    try {
        for (int col = 0; col < size; ++col) {
            for (int row = 0; row < size; ++row) {

                final int x = row * tileWidth;
                final int y = col * tileHeight;
                final SnapshotParameters params = new SnapshotParameters();
                params.setViewport(new Rectangle2D(x, y, tileWidth, tileHeight));   

                final CompletableFuture<Image> future = new CompletableFuture<>();

                // keeps fx application thread unblocked
                Platform.runLater(() -> future.complete(node.snapshot(params, null)));
                full.getPixelWriter().setPixels(x, y, tileWidth, tileHeight, future.get().getPixelReader(), 0, 0);
            }
        }

        System.out.println("Exporting node (saving to file)");

        ImageIO.write(SwingFXUtils.fromFXImage(full, null), "png", new File(filePath));

        System.out.println("Exporting node (finished)");

    } catch (Exception e) {
        e.printStackTrace();
    }
}