2016-11-16 2 views
1

Конечная цель - записать вывод WebView со скоростью 30 кадров в секунду или лучше, возможно, установив FBO для javafx? Тогда я мог бы вытащить фреймы во все рамки, которые я хотел.Попытка визуализации javafx WebView в буфер вне экрана или FBO

Я пробормотал некоторых, и я столкнулся с UploadingPainter в ViewScene, что заставляет меня думать, что это возможно. Борьба в том, что это, по-видимому, под капотом и несколько нова для меня.

Кто-нибудь знает способ сделать что-то вроде этой работы?

Это код, который я наткнулся во время отладки:

@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

Вот пример захвата анимации в WebView.

Изображения, снятые с веб-представления, размещаются в Paginator для просмотра, так что их легко просмотреть. Вы можете использовать SwingFXUtils и ImageIO, чтобы записать их в файлы, если хотите. Если вы хотите получить результирующие изображения в буфер, вы можете использовать их PixelReader.

first second

Это не совсем работает так, как я хотел. Я хотел сделать снимок 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); } 
} 

Для тонкой настройки захвата последовательности анимации, вы могли бы рассмотреть этот 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

Безголовая порт использует реализацию LinuxInputDeviceRegistry из InputDeviceRegistry.Однако безгонный порт не имеет доступа к каким-либо фактическим устройствам Linux или к любым родным API; он использует входной реестр Linux в режиме моделирования устройств. Это позволяет моделировать вход устройства Linux даже на платформах, отличных от Linux. Тесты в тестах/system/src/test/java/com/sun/glass/ui/monocle/input широко используют эту функцию.

Если подход, основанный на JavaFX Монокля заканчивается не работает для вас, вы могли бы рассмотреть другую (не JavaFX), связанный обезглавленный набор рендеринга HTML, такие как PhantomJS.

+0

Безголовый - это ключ, в моем случае. Спрашиваемые машины (linux) запускаются в серверной ферме совершенно безголовыми. Что касается сути, я вижу шоу() там, но я присмотрюсь ближе, чтобы убедиться, что я ничего не забыл. Благодаря! – lagnat

Смежные вопросы