下面是在 WebView 中捕获动画的示例。
从网络视图捕获的图像被放置在分页器中以供查看,以便于查看它们。你可以使用SwingFXUtils
and ImageIO
如果您愿意,可以将它们写到文件中。如果你想将生成的图像放入缓冲区,你可以使用它们PixelReader
.
它并不完全按照我想要的方式工作。我想拍摄 WebView 的快照,而不将其放置在可见的舞台上。拍摄不在 Stage 中的节点的快照对于 JavaFX 中的所有其他节点类型都可以正常工作(据我所知),但是,由于某些奇怪的原因,它不适用于 WebView。因此,该示例实际上在显示窗口后面创建了一个新的 Stage,用于显示动画捕获结果的图像序列。我知道这不完全是你想要的,但它就是这样......
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.*;
import javafx.concurrent.Worker;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class WebViewAnimationCaptor extends Application {
private static final String CAPTURE_URL =
"https://upload.wikimedia.org/wikipedia/commons/d/dd/Muybridge_race_horse_animated.gif";
private static final int N_CAPS_PER_SECOND = 10;
private static final int MAX_CAPTURES = N_CAPS_PER_SECOND * 5;
private static final int W = 186, H = 124;
class CaptureResult {
ObservableList<Image> images = FXCollections.observableArrayList();
DoubleProperty progress = new SimpleDoubleProperty();
}
@Override public void start(Stage stage) {
CaptureResult captures = captureAnimation(CAPTURE_URL);
Pane captureViewer = createCaptureViewer(captures);
stage.setScene(new Scene(captureViewer, W + 40, H + 80));
stage.show();
}
private StackPane createCaptureViewer(CaptureResult captures) {
ProgressIndicator progressIndicator = new ProgressIndicator();
progressIndicator.progressProperty().bind(captures.progress);
progressIndicator.setPrefSize(W, H);
StackPane stackPane = new StackPane(progressIndicator);
stackPane.setPadding(new Insets(10));
if (captures.progress.get() >= 1.0) {
stackPane.getChildren().setAll(
createImagePages(captures.images)
);
} else {
captures.progress.addListener((observable, oldValue, newValue) -> {
if (newValue.doubleValue() >= 1.0) {
stackPane.getChildren().setAll(
createImagePages(captures.images)
);
}
});
}
return stackPane;
}
private Pagination createImagePages(ObservableList<Image> captures) {
Pagination pagination = new Pagination();
pagination.setPageFactory(param -> {
ImageView currentImage = new ImageView();
currentImage.setImage(
param < captures.size()
? captures.get(param)
: null
);
StackPane pageContent = new StackPane(currentImage);
pageContent.setPrefSize(W, H);
return pageContent;
});
pagination.setCurrentPageIndex(0);
pagination.setPageCount(captures.size());
pagination.setMaxPageIndicatorCount(captures.size());
return pagination;
}
private CaptureResult captureAnimation(final String url) {
CaptureResult captureResult = new CaptureResult();
WebView webView = new WebView();
webView.getEngine().load(url);
webView.setPrefSize(W, H);
Stage captureStage = new Stage();
captureStage.setScene(new Scene(webView, W, H));
captureStage.show();
SnapshotParameters snapshotParameters = new SnapshotParameters();
captureResult.progress.set(0);
AnimationTimer timer = new AnimationTimer() {
long last = 0;
@Override
public void handle(long now) {
if (now > last + 1_000_000_000.0 / N_CAPS_PER_SECOND) {
last = now;
captureResult.images.add(webView.snapshot(snapshotParameters, null));
captureResult.progress.setValue(
captureResult.images.size() * 1.0 / MAX_CAPTURES
);
}
if (captureResult.images.size() > MAX_CAPTURES) {
captureStage.hide();
this.stop();
}
}
};
webView.getEngine().getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
if (Worker.State.SUCCEEDED.equals(newValue)) {
timer.start();
}
});
return captureResult;
}
public static void main(String[] args) { launch(args); }
}
要微调动画序列捕获,您可以查看此JavaFX 中的动画计时器信息 http://svanimpe.be/blog/game-loops-fx.html.
如果你需要让这个东西“无头”,这样就不需要可见的舞台,你可以尝试这个danialfarid 的要点,它执行“Java 图像捕获、HTML 快照、HTML 到图像” https://gist.github.com/danialfarid/2ddbab04803ae4fd2dca(虽然我没有写链接的要点,也没有尝试过)。
对我来说,无头是关键。有问题的(linux)机器在完全无头的服务器场中运行。至于要点,我在那里看到了一个 show() ,但我会仔细看看以确保我没有忽略某些东西。
要点是基于用于 JavaFX 系统的 Monocle 玻璃渲染工具包 https://wiki.openjdk.java.net/display/OpenJFX/Monocle。该工具包支持任何系统上基于软件的无头渲染。
来自单片眼镜文档 https://wiki.openjdk.java.net/download/attachments/17957197/Monocle.pdf?api=v2:
无头端口不执行任何操作。它适用于您想要在没有图形、输入或平台依赖性的情况下运行 JavaFX 的情况。渲染仍然发生,只是没有显示在屏幕上。
无头端口使用 InputDeviceRegistry 的 LinuxInputDeviceRegistry 实现。然而,无头端口根本不访问任何实际的 Linux 设备或任何本机 API;它在设备模拟模式下使用 Linux 输入注册表。这使得即使在非 Linux 平台上也可以模拟 Linux 设备输入。 tests/system/src/test/java/com/sun/glass/ui/monocle/input 中的测试广泛使用了此功能。
如果基于 JavaFX Monocle 的方法最终不适合您,您可以考虑另一个(与 JavaFX 无关)无头 HTML 渲染工具包,例如PhantomJS http://phantomjs.org.