【问题标题】:JavaFX 2.0+ WebView /WebEngine render web page to an imageJavaFX 2.0+ WebView /WebEngine 将网页呈现为图像
【发布时间】:2011-12-09 10:34:14
【问题描述】:

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

目前,在没有 JavaFX 的情况下,我通过从 java 调用外部进程并渲染到文件而不是将该文件加载到 ImageBuffer 中来做到这一点......既不是非常优化也不实用,甚至更不跨平台......

使用 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;
    }
}

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

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

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

canvasImagesaveImage(canvasImage, fc.getSelectedFile()) 来自这个:

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

其他:

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/

【问题讨论】:

    标签: java image save render javafx


    【解决方案1】:

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

    您可以按照本教程制作 WebView:Integrating JavaFX into Swing Applications

    下面的代码演示了我如何从 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();
    }
    

    【讨论】:

    • 我会使用printprintAll 而不是paint,但基本的想法很酷!
    • 什么是 FXBrowser?
    【解决方案2】:

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

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

    这是一个从 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);
       }
    

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

    希望对您有所帮助!

    【讨论】:

    • 但是无头截图呢?所以我可以在服务器端启动它来截取像 PhantomJS 一样的屏幕截图
    • 对不起,我不明白你的意思
    • 我只是在寻找可以拍摄快照但不显示任何形式/框架的工作示例 - “无头”。就像启动应用程序一样,它会拍摄我通过的任何 html 的快照,而不会在屏幕上显示任何窗口。就像 PhantomJS 一样。
    【解决方案3】:

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

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

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

    【讨论】:

    • 你有没有让这个工作?我无法让 WebView 向图像写入任何内容,除非我将它实际附加到场景并在舞台上显示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 2016-04-21
    • 1970-01-01
    • 2013-01-01
    • 2015-10-06
    • 1970-01-01
    • 2013-11-03
    相关资源
    最近更新 更多