2016-11-16 48 views
1

最终目标是能够以30fps或更高的速度记录WebView的输出,也许可以通过为javafx设置FBO来记录输出。然后我可以以我想要的任何帧率抽出帧。试图将javafx WebView渲染为离线缓冲区或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); 
    } 
} 

回答

2

这里是在web视图拍摄动画的一个例子。

从网络视图捕获的图像被放置在Paginator中进行查看,以便查看它们。如果您愿意,您可以使用SwingFXUtilsImageIO将它们写出到文件中。如果你想将得到的图像存入缓冲区,你可以使用它们的PixelReader

first second

这完全不是那么回事我想它的方式。我想快照WebView而不将其放置在可见的舞台上。但是,对于不在舞台中的节点拍摄快照对于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); } 
} 

要微调动画序列捕获,你可以审查这个info on AnimationTimers in JavaFX

如果你需要让事物“无头”,以便不需要可见的舞台,你可以试试gist by danialfarid which performs "Java Image Capture, HTML Snapshot, HTML to image"(尽管我没有写出链接的要点,但没有尝试过)。


无头是关键,在我的情况。有问题的(linux)机器在服务器场中完全无法运行。至于主旨,我在那里看到一个节目(),但我会仔细观察一下,以确保我没有忽略某些东西。

该要点基于Monocle glass rendering toolkit for JavaFX systems。该工具包支持在任何系统上进行基于软件的无头渲染。

Monocle Documentation

无头端口什么都不做。当你想运行没有图形,输入或平台依赖的JavaFX时。渲染仍然发生,它只是不显示在屏幕上。

headless operation

无头端口使用InputDeviceRegistry的LinuxInputDeviceRegistry执行。然而,无头端口根本不访问任何实际的Linux设备或任何本地API;它在设备模拟模式下使用Linux输入注册表。这样即使在非Linux平台上也可以模拟Linux设备输入。 tests/system/src/test/java/com/sun/glass/ui/monocle/input中的测试广泛使用了此功能。

如果JavaFX的单片眼镜基础的做法最终不会为你工作了,你可以考虑另一种(不相关的JavaFX)无头的HTML渲染套件,如PhantomJS

+0

无头是我的关键。有问题的(linux)机器在服务器场中完全无法运行。至于主旨,我在那里看到一个节目(),但我会仔细观察一下,以确保我没有忽略某些东西。谢谢! – lagnat

相关问题