正在尝试将javafx WebView渲染到屏幕外缓冲区或FBO

正在尝试将javafx WebView渲染到屏幕外缓冲区或FBO,javafx,jogl,Javafx,Jogl,最终目标是能够以30fps或更高的速度记录WebView的输出,可能是通过为javafx设置FBO?然后,我可以以我想要的任何帧速率拉出帧 我翻了一些,在ViewScene中遇到了UploadingPainter,这让我觉得这是可能的。斗争是,这似乎是在幕后,对我来说有些新鲜 有人知道这样做的方法吗 这是我在调试过程中遇到的代码: @Override public void setStage(GlassStage stage) { super.setStage(stage); i

最终目标是能够以30fps或更高的速度记录WebView的输出,可能是通过为javafx设置FBO?然后,我可以以我想要的任何帧速率拉出帧

我翻了一些,在ViewScene中遇到了UploadingPainter,这让我觉得这是可能的。斗争是,这似乎是在幕后,对我来说有些新鲜

有人知道这样做的方法吗

这是我在调试过程中遇到的代码:

@Override
public void setStage(GlassStage stage) {
    super.setStage(stage);
    if (stage != null) {
        WindowStage wstage  = (WindowStage)stage;
        if (wstage.needsUpdateWindow() || GraphicsPipeline.getPipeline().isUploading()) {
            if (Pixels.getNativeFormat() != Pixels.Format.BYTE_BGRA_PRE ||
                ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {
                throw new UnsupportedOperationException(UNSUPPORTED_FORMAT);
            }
            painter = new UploadingPainter(this);
        } else {
            painter = new PresentingPainter(this);
        }
        painter.setRoot(getRoot());
        paintRenderJob = new PaintRenderJob(this, PaintCollector.getInstance().getRendered(), painter);
    }
}

下面是在WebView中捕获动画的示例

从web视图中捕获的图像被放置在分页器中,以便于查看。如果愿意,您可以使用
SwingFXUtils
ImageIO
将它们写入文件。如果要将生成的图像放入缓冲区,可以使用它们的
PixelReader

它没有按照我想要的方式工作。我想在不将WebView置于可见阶段的情况下对其进行快照。拍摄不在某个阶段的节点的快照对于JavaFX中的所有其他节点类型都很好(据我所知),但是,出于某种奇怪的原因,它不适用于WebView。因此,该示例实际上在显示窗口后面创建了一个新的阶段,用于显示动画捕获结果的图像序列。我知道这不完全是你想要的,但它是什么

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.animation.AnimationTimer;
导入javafx.application.application;
导入javafx.beans.property.*;
导入javafx.collections.*;
导入javafx.concurrent.Worker;
导入javafx.geometry.Insets;
导入javafx.scene.scene;
导入javafx.scene.Snapshot参数;
导入javafx.scene.control.*;
导入javafx.scene.image.*;
导入javafx.scene.layout.*;
导入javafx.scene.web.WebView;
导入javafx.stage.stage;
公共类WebViewAnimationCaptor扩展应用程序{
私有静态最终字符串捕获\u URL=
"https://upload.wikimedia.org/wikipedia/commons/d/dd/Muybridge_race_horse_animated.gif";
私有静态最终整数N_CAPS_/秒=10;
私有静态最终int MAX_CAPTURES=N_CAPS_PER_SECOND*5;
专用静态最终int W=186,H=124;
类捕获结果{
ObservableList images=FXCollections.observableArrayList();
DoubleProperty progress=新的SimpleDoubleProperty();
}
@覆盖公共无效开始(阶段){
CaptureResult captures=captureAnimation(捕获URL);
窗格captureViewer=createCaptureViewer(捕获);
舞台场景(新场景(captureViewer,W+40,H+80));
stage.show();
}
私有堆栈窗格createCaptureViewer(CaptureResult捕获){
ProgressIndicator ProgressIndicator=新的ProgressIndicator();
progressIndicator.progressProperty().bind(captures.progress);
progressIndicator.setPrefSize(宽、高);
StackPane StackPane=新的StackPane(进度指示器);
stackPane.setPadding(新插图(10));
if(captures.progress.get()>=1.0){
stackPane.getChildren().setAll(
createImagePages(captures.images)
);
}否则{
captures.progress.addListener((可观察、旧值、新值)->{
如果(newValue.doubleValue()>=1.0){
stackPane.getChildren().setAll(
createImagePages(captures.images)
);
}
});
}
返回堆栈窗格;
}
专用分页createImagePages(可观察列表捕获){
分页分页=新分页();
分页。setPageFactory(参数->{
ImageView currentImage=新建ImageView();
currentImage.setImage(
param上一次+1_000_000.0/N_CAPS_/秒){
最后=现在;
capturesult.images.add(webView.snapshot(快照参数,null));
captureResult.progress.setValue(
captureResult.images.size()*1.0/MAX\u捕获
);
}
if(captureResult.images.size()>MAX_捕获){
captureStage.hide();
这个。停止();
}
}
};
webView.getEngine().getLoadWorker().stateProperty().addListener((可观察、旧值、新值)->{
if(Worker.State.successed.equals(newValue)){
timer.start();
}
});
返回捕获结果;
}
公共静态void main(字符串[]args){launch(args);}
}
若要微调动画序列捕获,可以查看此内容

如果你需要把东西做成“无头”,这样就可以看到