简体   繁体   English

JavaFX 2.0+ WebView / WebEngine将网页呈现给图像

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

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 : renderToImage in 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

canvasImage and 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/

I have done this by launching JavaFX WebView on a Swing JFrame and JFXPanel. 我通过在Swing JFrame和JFXPanel上启动JavaFX WebView来完成此操作。 And then I use the paint() method on JFXPanel once the WebEngine status is SUCCEEDED. 然后,一旦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();
}

For JavaFX 2.2 users there is a much more clean and elegant solution based on JavaFX Node snapshot. 对于JavaFX 2.2用户,基于JavaFX Node快照有一个更加干净和优雅的解决方案。 You can take a look to JavaFX node documentation at: 您可以在以下位置查看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. 我对此解决方案没有任何问题,并且根据节点大小在WebG中完美呈现webview。 Any JavaFx node can be rendered and saved to a file with this method. 可以使用此方法呈现任何JavaFx节点并将其保存到文件中。

Hope this help! 希望这有帮助!

Workaround posted by JavaFX engineers: Snapshot does not work with (invisible) WebView nodes . JavaFX工程师发布的解决方法: 快照不适用于(不可见的)WebView节点

When taking a snapshot of a scene that contains a WebView node, wait for at least 2 frames before issuing the snapshot command. 拍摄包含WebView节点的场景的快照时,请在发出快照命令之前至少等待2帧。 This can be done by using a counter in an AnimationTimer to skip 2 pulses and take the snapshot on the 3rd pulse. 这可以通过使用AnimationTimer中的计数器跳过2个脉冲并在第3个脉冲上拍摄快照来完成。

Once you have got your snapshot, you can convert the image to an awt BufferedImage and encode the image to format like png or jpg, using ImageIO . 获得快照后,您可以将图像转换为awt BufferedImage,并使用ImageIO将图像编码为png或jpg等格式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM