2016-11-16 129 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

相關問題