JDK-8087569 : Snapshot does not work with (invisible) WebView nodes
  • Type: Bug
  • Component: javafx
  • Sub-Component: web
  • Affected Version: 7u6
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2012-07-06
  • Updated: 2018-09-05
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Description
Snapshot only works when pressing on (uncommented) snapshot button. In this case the WebView was rendered on screen before, otherwise the png only shows the test-label.

private final String INITIAL_TEXT = "<head></head><body><p style=\"text-align: center; font-size:36pt;\"><font face=\"Arial\">emptyText</font></p></body>";

	@Override
	public void start(Stage stage) {
		stage.setTitle("WebView Snapshot Sample");
		stage.setWidth(500);
		stage.setHeight(500);
		Scene scene = new Scene(new Group());

		final VBox root = new VBox();
		root.setPadding(new Insets(8, 8, 8, 8));
		root.setSpacing(5);

		WebView webView = new WebView();
		webView.getEngine().loadContent(INITIAL_TEXT);

		//		Button snapshotButton = new Button("Snapshot");
		//		snapshotButton.setOnAction(new EventHandler<ActionEvent>() {
		//
		//			@Override
		//			public void handle(ActionEvent arg0) {
		//				createSnapShot(root);
		//			}
		//		});
		//
		//		root.getChildren().addAll(webView, new Label("Test Label"), snapshotButton);
		root.getChildren().addAll(webView, new Label("Test Label"));

		scene.setRoot(root);
		stage.setScene(scene);

		createSnapShot(root);

		stage.show();
	}

	private void createSnapShot(final Node node) {
		Platform.runLater(new Runnable() {

			@Override
			public void run() {
				SnapshotParameters params = new SnapshotParameters();
				Image image = node.snapshot(params, null);
				System.out.println("snapshot image created");

				try {
					ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", new File("d:\\output.png"));
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		});
	}

	public static void main(String[] args) {
		launch(args);
	}
Comments
I tested with the following code. It works, when I display the WebView in a Stage. In other words, when I remove the comments in the code below. According to the documentation of Node.snapshot() it should also work, if the WebView is only attached to a Scene and therefore not visible. Is there a way to create a snapshot from an invisible WebView? final String html = "<head></head><body><p style=\"text-align: left; font-size:36pt;\"><font face=\"Arial\">emptyText</font></p></body>"; final int width = 500; final int height = 500; final WritableImage image = new WritableImage(width, height); Platform.runLater(new Runnable() { @Override public void run() { final WebView browser = new WebView(); Scene scene = new Scene(browser); // final Stage stage = new Stage(); // stage.show(); // stage.setScene(scene); browser.setPrefSize(width, height); WebEngine webEngine = browser.getEngine(); webEngine.getLoadWorker().stateProperty().addListener( new ChangeListener<State>() { public void changed(ObservableValue ov, State oldState, State newState) { if (newState == State.SUCCEEDED) { final AnimationTimer animationTimer = new AnimationTimer() { private int pulseCounter; @Override public void handle(long arg0) { pulseCounter++; if(pulseCounter > 2) { stop(); browser.snapshot(new SnapshotParameters(), image); // stage.close(); countDownLatch.countDown(); } } }; animationTimer.start(); } } }); webEngine.loadContent(html); } }); countDownLatch.await(10, TimeUnit.SECONDS); return image; }
30-06-2014

Is there any way for the developer to force the WebView to render when it is not displayed?
27-10-2013

hi Kevin, how to use AnimationTimer to skip first 2 frames? any code snippet? thanks
15-03-2013

WebView rendering architecture is based on pulses mostly (or even solely) because of controls WebView "borrows" from jfx. A control rendered within a web page, as it changes its geometry or state should pass through css/layout/sync procedures before it can be repainted. These procedures are performed during a pulse. So, we can't untie from pulses until we change the way we render controls (if that is at all possible).
28-09-2012

All WebEngine load operations, including WebEgnine.loadContent, are asynchronous, so one needs to wait for the page to load (via the object returned by WebEngine.getLoadWorker()) to be sure WebView has something to display. However, even if you wait for the page to load and after that call Node.snapshot, either directly or through Platffrom.runLater, WebView will still not render its new content. The problem is, in this case no pulses occur in between the load completion event and the call to Node.snapshot, and, without pulses, WebView will not generate any render work and will not mark itself dirty. The right solution to this would be to either change the WebView rendering architecture altogether to stop relying on pulses (not sure yet if that is at all possible), or have Node.snapshot do a pulse internally. This problem is orthogonal to RT-25219.
28-09-2012

Something to consider while fixing RT-25219.
26-09-2012

SQE / OK
19-07-2012

Workaround for 2.2: When taking a snapshot of a scene that contains a WebView node, wait for at least 2 frames before issuing the snapshot command. This can be done by using a counter in an AnimationTimer to skip 2 pulses and take the snapshot on the 3rd pulse.
19-07-2012

This looks like a bug in WebView. I verified that the first frame rendered to the Stage after the show method does not contain the webnode. Only after the second frame is rendered does the WebView show up. Taking a snapshot in the start method renders the same thing as the first frame. As I mentioned above, this is too late for 2.2, and there is a workaround, so I will defer this to 3.0, assign it to the WebView team, and document the workaround in the release notes.
19-07-2012

I can reproduce this with the current 2.2 build. I also note that setting an animation timer to, say, 300 msec also allows it to work. Not sure if the bug is in WebView or in Graphics (snapshot). I'll take a look at it, but unless there is a trivial fix, it is too late for 2.2.
10-07-2012