JavaFX 2.0+ WebView /WebEngine 将网页呈现为图像
Posted
技术标签:
【中文标题】JavaFX 2.0+ WebView /WebEngine 将网页呈现为图像【英文标题】:JavaFX 2.0+ WebView /WebEngine render web page to an image 【发布时间】: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
canvasImage
和 saveImage(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/
【问题讨论】:
【参考方案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();
【讨论】:
我会使用print
或printAll
而不是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 向图像写入任何内容,除非我将它实际附加到场景并在舞台上显示。以上是关于JavaFX 2.0+ WebView /WebEngine 将网页呈现为图像的主要内容,如果未能解决你的问题,请参考以下文章
JavaFX : 使用 JavaFX 嵌入浏览器而不是可用的 webview