java JavaFX 2.0+ WebView /WebEngine 将网页渲染为图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7796558/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 21:29:28  来源:igfitidea点击:

JavaFX 2.0+ WebView /WebEngine render web page to an image

javaimagesaverenderjavafx

提问by leroyse

I'm looking for a way to load up a page and save the rendering as an image just as you would do with CutyCapt (QT + webkit EXE to do just that).

我正在寻找一种方法来加载页面并将渲染保存为图像,就像使用 CutyCapt 一样(QT + webkit EXE 可以做到这一点)。

At the moment and without JavaFX, I do it by calling an external process from java and rendering to file than loading that file into an ImageBuffer... Neither very optimized nor practical and even less cross platform...

目前,在没有 JavaFX 的情况下,我通过从 Java 调用外部进程并将其渲染到文件而不是将该文件加载到 ImageBuffer...

Using JavaFX2+ I tried playing with the WebView & WebEngine:

使用 JavaFX2+ 我尝试使用 WebView 和 WebEngine:

public class WebComponentTrial extends Application {
    private Scene scene;

    @Override
    public void start(final Stage primaryStage) throws Exception {
        primaryStage.setTitle("Web View");
        final Browser browser = new Browser();
        scene = new Scene(browser, 1180, 800, Color.web("#666970"));
        primaryStage.setScene(scene);
        scene.getStylesheets().add("webviewsample/BrowserToolbar.css");
        primaryStage.show();
    }

    public static void main(final String[] args) {
        launch(args);
    }
}
class Browser extends Region {
    static { // use system proxy settings when standalone application
    // System.setProperty("java.net.useSystemProxies", "true");
    }

    final WebView browser = new WebView();
    final WebEngine webEngine = browser.getEngine();

    public Browser() {
        getStyleClass().add("browser");
        webEngine.load("http://www.google.com/");
        getChildren().add(browser);
    }

    @Override
    protected void layoutChildren() {
        final double w = getWidth();
        final double h = getHeight();
        layoutInArea(browser, 0, 0, w, h, 0, HPos.CENTER, VPos.CENTER);
    }

    @Override
    protected double computePrefWidth(final double height) {
        return 800;
    }

    @Override
    protected double computePrefHeight(final double width) {
        return 600;
    }
}

There is a deprecated method : renderToImagein Scene(see links below) that would do something that comes close and with which I'd might be able to work but it is deprecated... It being deprecated in JavaFX seems to mean that there is no javadoc advertising the replacement method and because I don't have access to the code, I cannot see how it was done...

有一个不推荐使用的方法:renderToImageScene(见下面的链接)中,它会做一些接近的事情,我可能可以使用它,但它已被弃用......它在 JavaFX 中被弃用似乎意味着没有 javadoc广告替换方法,因为我无法访问代码,所以我看不到它是如何完成的......

Here are a couple of sites where I found some information but nothing to render a webpage to an image:

这里有几个网站,我在其中找到了一些信息,但没有将网页渲染为图像:

http://tornorbye.blogspot.com/2010/02/how-to-render-javafx-node-into-image.html

canvasImageand saveImage(canvasImage, fc.getSelectedFile())from this one :

canvasImagesaveImage(canvasImage, fc.getSelectedFile())从这个:

http://javafx.com/samples/EffectsPlayground/src/Main.fx.html

Others:

其他:

http://download.oracle.com/javafx/2.0/webview/jfxpub-webview.htm
http://download.oracle.com/javafx/2.0/get_started/jfxpub-get_started.htm
http://fxexperience.com/2011/05/maps-in-javafx-2-0/

采纳答案by Antony.H

I have done this by launching JavaFX WebView on a Swing JFrame and JFXPanel. And then I use the paint() method on JFXPanel once the WebEngine status is SUCCEEDED.

我通过在 Swing JFrame 和 JFXPanel 上启动 JavaFX WebView 来做到这一点。然后,一旦 WebEngine 状态为 SUCCEEDED,我就在 JFXPanel 上使用paint() 方法。

You may follow this tutorial to make a WebView: Integrating JavaFX into Swing Applications

您可以按照本教程制作 WebView:将 JavaFX 集成到 Swing 应用程序中

The code below demonstrate how I capture the rendered screen from JFXPanel.

下面的代码演示了我如何从 JFXPanel 捕获渲染的屏幕。

public static void main(String args[]) {
    jFrame = new JFrame("Demo Browser");
    jfxPanel = new JFXPanel();
    jFrame.add(jfxPanel);
    jFrame.setVisible(true);
    jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    browser = new FXBrowser();
                    jfxPanel.setScene(browser.getScene());
                    jFrame.setSize((int) browser.getWebView().getWidth(), (int) browser.getWebView().getHeight());

                    browser.getWebEngine().getLoadWorker().stateProperty().addListener(
                            new ChangeListener() {
                                @Override
                                public void changed(ObservableValue observable,
                                                    Object oldValue, Object newValue) {
                                    State oldState = (State) oldValue;
                                    State newState = (State) newValue;
                                    if (State.SUCCEEDED == newValue) {
                                        captureView();
                                    }
                                }
                            });
                }
            });
        }
    });
}

private static void captureView() {
    BufferedImage bi = new BufferedImage(jfxPanel.getWidth(), jfxPanel.getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics graphics = bi.createGraphics();
    jfxPanel.paint(graphics);
    try {
        ImageIO.write(bi, "PNG", new File("demo.png"));
    } catch (IOException e) {
        e.printStackTrace();
    }
    graphics.dispose();
    bi.flush();
}

回答by Alvaro Luis Bustamante

For JavaFX 2.2 users there is a much more clean and elegant solution based on JavaFX Node snapshot. You can take a look to JavaFX node documentation at:

对于 JavaFX 2.2 用户,有一个基于 JavaFX 节点快照的更简洁优雅的解决方案。您可以在以下位置查看 JavaFX 节点文档:

http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html

http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html

Here is an example of taking a capture from a WebView Node (as webView)

这是从 WebView 节点(作为 webView)进行捕获的示例

   File destFile = new File("test.png");
   WritableImage snapshot = webView.snapshot(new SnapshotParameters(), null);
   RenderedImage renderedImage = SwingFXUtils.fromFXImage(snapshot, null);
   try {
       ImageIO.write(renderedImage, "png", destFile);
   } catch (IOException ex) {
       Logger.getLogger(GoogleMap.class.getName()).log(Level.SEVERE, null, ex);
   }

I had no problems with this solution, and the webview is rendered perfectly in the PNG according to the node size. Any JavaFx node can be rendered and saved to a file with this method.

我对这个解决方案没有任何问题,并且根据节点大小在 PNG 中完美呈现了 webview。可以使用此方法呈现任何 JavaFx 节点并将其保存到文件中。

Hope this help!

希望这有帮助!

回答by jewelsea

Workaround posted by JavaFX engineers: Snapshot does not work with (invisible) WebView nodes.

JavaFX 工程师发布的解决方法:Snapshot does not work with (invisible) WebView nodes

When taking a snapshot of a scene that contains a WebViewnode, wait for at least 2 frames before issuing the snapshotcommand. This can be done by using a counter in an AnimationTimerto skip 2 pulses and take the snapshot on the 3rd pulse.

拍摄包含WebView节点的场景的快照时,在发出快照命令之前至少等待 2 帧。这可以通过在AnimationTimer 中使用计数器跳过 2 个脉冲并在第 3 个脉冲上拍摄快照来完成。

Once you have got your snapshot, you can convert the image to an awt BufferedImageand encode the image to format like png or jpg, using ImageIO.

获得快照后,您可以使用ImageIO将图像转换为 awt BufferedImage并将图像编码为 png 或 jpg 等格式。