JavaFX 2.0+ WebView / WebEngine отображает веб-страницу в изображение - PullRequest
10 голосов
/ 17 октября 2011

Я ищу способ загрузить страницу и сохранить рендеринг как изображение так же, как вы сделали бы это с CutyCapt (QT + webkit EXE, чтобы сделать это).

В настоящий момент и без JavaFX я делаю это, вызывая внешний процесс из Java и рендеринг в файл, а не загружая этот файл в ImageBuffer ... Ни очень оптимизированный, ни практичный, и даже менее кроссплатформенный ...

Использование JavaFX2 + Я попытался поиграть с WebView & WebEngine:

public class WebComponentTrial extends Application {
    private Scene scene;

    @Override
    public void start(final Stage primaryStage) throws Exception {
        primaryStage.setTitle("Web View");
        final Browser browser = new Browser();
        scene = new Scene(browser, 1180, 800, Color.web("#666970"));
        primaryStage.setScene(scene);
        scene.getStylesheets().add("webviewsample/BrowserToolbar.css");
        primaryStage.show();
    }

    public static void main(final String[] args) {
        launch(args);
    }
}
class Browser extends Region {
    static { // use system proxy settings when standalone application
    // System.setProperty("java.net.useSystemProxies", "true");
    }

    final WebView browser = new WebView();
    final WebEngine webEngine = browser.getEngine();

    public Browser() {
        getStyleClass().add("browser");
        webEngine.load("http://www.google.com/");
        getChildren().add(browser);
    }

    @Override
    protected void layoutChildren() {
        final double w = getWidth();
        final double h = getHeight();
        layoutInArea(browser, 0, 0, w, h, 0, HPos.CENTER, VPos.CENTER);
    }

    @Override
    protected double computePrefWidth(final double height) {
        return 800;
    }

    @Override
    protected double computePrefHeight(final double width) {
        return 600;
    }
}

Существует устаревший метод: renderToImage в Scene (см. Ссылки ниже), который будет делать что-то, что приходитзакрыть и с которым я мог бы работать, но это устарело ... Это устарело в JavaFX, кажется, означает, что нет никакого javadoc, рекламирующего метод замены, и потому что у меня нет доступа к коду, я не могупосмотрим, как это было сделано ...

Вот несколько сайтов, на которых я нашел некоторую информацию, но ничего не смог отобразить веб-страницу с изображением:

http://tornorbye.blogspot.com/2010/02/how-to-render-javafx-node-into-image.html

canvasImage и saveImage(canvasImage, fc.getSelectedFile()) из этого:

http://javafx.com/samples/EffectsPlayground/src/Main.fx.html

Другие:

http://download.oracle.com/javafx/2.0/webview/jfxpub-webview.htm
http://download.oracle.com/javafx/2.0/get_started/jfxpub-get_started.htm
http://fxexperience.com/2011/05/maps-in-javafx-2-0/

Ответы [ 3 ]

9 голосов
/ 18 июля 2012

Я сделал это, запустив JavaFX WebView на Swing JFrame и JFXPanel. И затем я использую метод paint () в JFXPanel, когда статус WebEngine становится SUCCEEDED.

Вы можете следовать этому руководству для создания WebView: Интеграция JavaFX в приложения Swing

Приведенный ниже код демонстрирует, как я получаю обработанный экран из JFXPanel.

public static void main(String args[]) {
    jFrame = new JFrame("Demo Browser");
    jfxPanel = new JFXPanel();
    jFrame.add(jfxPanel);
    jFrame.setVisible(true);
    jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    browser = new FXBrowser();
                    jfxPanel.setScene(browser.getScene());
                    jFrame.setSize((int) browser.getWebView().getWidth(), (int) browser.getWebView().getHeight());

                    browser.getWebEngine().getLoadWorker().stateProperty().addListener(
                            new ChangeListener() {
                                @Override
                                public void changed(ObservableValue observable,
                                                    Object oldValue, Object newValue) {
                                    State oldState = (State) oldValue;
                                    State newState = (State) newValue;
                                    if (State.SUCCEEDED == newValue) {
                                        captureView();
                                    }
                                }
                            });
                }
            });
        }
    });
}

private static void captureView() {
    BufferedImage bi = new BufferedImage(jfxPanel.getWidth(), jfxPanel.getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics graphics = bi.createGraphics();
    jfxPanel.paint(graphics);
    try {
        ImageIO.write(bi, "PNG", new File("demo.png"));
    } catch (IOException e) {
        e.printStackTrace();
    }
    graphics.dispose();
    bi.flush();
}
7 голосов
/ 17 июля 2013

Для пользователей JavaFX 2.2 существует гораздо более чистое и элегантное решение, основанное на моментальном снимке узла JavaFX.Вы можете взглянуть на документацию узла JavaFX по адресу:

http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html

Вот пример получения захвата от узла WebView (как webView)

   File destFile = new File("test.png");
   WritableImage snapshot = webView.snapshot(new SnapshotParameters(), null);
   RenderedImage renderedImage = SwingFXUtils.fromFXImage(snapshot, null);
   try {
       ImageIO.write(renderedImage, "png", destFile);
   } catch (IOException ex) {
       Logger.getLogger(GoogleMap.class.getName()).log(Level.SEVERE, null, ex);
   }

У меня не было проблем с этим решением, и веб-просмотр отлично отображается в формате PNG в соответствии с размером узла.С помощью этого метода можно отобразить любой узел JavaFx и сохранить его в файле.

Надеюсь, эта помощь!

2 голосов
/ 03 декабря 2012

Обход, опубликованный инженерами JavaFX: Снимок не работает с (невидимыми) узлами WebView .

При создании снимка сцены, содержащей WebView *Узел 1007 *, подождите как минимум 2 кадра, прежде чем вводить команду snapshot .Это можно сделать с помощью счетчика в AnimationTimer , чтобы пропустить 2 импульса и сделать снимок 3-го импульса.

Получив снимок, вы можете преобразовать изображение в awt BufferedImage и кодировать изображение в формат, подобный png или jpg, используя ImageIO .

...