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

10
我正在寻找一种加载页面并将其渲染为图片的方法,就像使用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;
    }
}

有一个过时的方法:renderToImageScene 中 (见下面的链接) 可以做一些接近的事情,我可能可以使用它,但它已经被弃用了...在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/
3个回答

10

我通过在 Swing JFrame 和 JFXPanel 上启动 JavaFX WebView 来完成这个操作。然后,在 WebEngine 状态为 SUCCEEDED 时,我使用 JFXPanel 上的 paint() 方法。

您可以按照此教程创建一个 WebView:将 JavaFX 集成到 Swing 应用程序中

以下代码演示了如何从 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,但基本思路非常酷! - MadProgrammer
FXBrowser是什么? - pupeno

10

对于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一样进行截屏。 - ses
抱歉,我不明白你的意思。 - Alvaro Luis Bustamante
1
我只是在寻找一个能够在“无头”模式下拍摄快照的工作示例,即启动应用程序,在不显示任何窗口的情况下拍摄我传递的任何HTML的快照。就像PhantomJS一样。 - ses

2

你最终解决了这个问题吗?我无法让 WebView 将任何东西写入图像,除非我将其附加到一个 Scene 并在舞台上显示它。 - matt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接