2011-10-17 9 views
10

Sto cercando un modo per caricare una pagina e salvare il rendering come un'immagine proprio come faresti con CutyCapt (QT + webkit EXE per fare proprio questo).JavaFX 2.0+ WebView/WebEngine esegue il rendering di una pagina Web su un'immagine

Al momento e senza JavaFX, lo faccio chiamando un processo esterno da Java e il rendering di file che caricare il file in un ImageBuffer ... Né molto ottimizzato né pratico e piattaforma ancora meno croce ...

Utilizzando JavaFX2 + ho provato a giocare con il 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; 
    } 
} 

C'è un metodo deprecato: renderToImage in Scene (vedi link sotto), che avrebbe fatto qualcosa che si avvicina e con la quale avrei potuto essere in grado lavorare ma è deprecato ... Essere deprecato in JavaFX sembra significare che non c'è javadoc che pubblicizza il metodo di sostituzione e perché non ho accesso al codice, non riesco a vedere come è stato fatto ...

Qui ci sono un paio di siti dove ho trovato un po 'di informazioni, ma niente di rendere una pagina web a un'immagine:

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

canvasImage e saveImage(canvasImage, fc.getSelectedFile()) da questo:

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

Altri:

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/ 

risposta

8

Ho fatto questo lanciando JavaFX WebView su uno Swing JFrame e JFXPanel. E poi uso il metodo paint() su JFXPanel una volta che lo stato di WebEngine è SUCCEEDED.

si può seguire questo tutorial per fare un WebView:

Il codice qui sotto dimostrano come ho catturare lo schermo reso da 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(); 
} 
+0

Io userei 'print' o' printAll' su 'paint', ma l'idea di base è WAY cool! – MadProgrammer

+0

Che cos'è FXBrowser? – Pablo

2

Soluzione pubblicato da ingegneri JavaFX: Snapshot does not work with (invisible) WebView nodes.

Quando scattare una fotografia di una scena che contiene un nodo WebView, attendere almeno 2 fotogrammi prima di emettere il comando snapshot. Questo può essere fatto utilizzando un contatore in un AnimationTimer per saltare 2 impulsi e scattare l'istantanea sul terzo impulso.

Una volta che avete ottenuto il vostro snapshot, è possibile convertire l'immagine in un AWT BufferedImage e codificare l'immagine per formattare come png o jpg, utilizzando ImageIO.

+2

il nuovo link al problema: https://bugs.openjdk.java.net/browse/JDK-8087569 –

7

Per gli utenti di JavaFX 2.2 è disponibile una soluzione molto più pulita ed elegante basata sullo snapshot Nodo JavaFX.Si può dare un'occhiata a JavaFX documentazione nodo:

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

Ecco un esempio di prendere una cattura da un nodo WebView (come 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); 
    } 

ho avuto problemi con questa soluzione e la visualizzazione Web viene resa perfettamente nel PNG in base alla dimensione del nodo. Qualsiasi nodo JavaFx può essere visualizzato e salvato in un file con questo metodo.

Spero che questo aiuto!

+0

Ma che ne dici di uno screenshot headless? così ho potuto lanciarlo sul lato server per scattare screenshot come con PhantomJS – ses

+0

Mi spiace, ma non ti capisco –

+1

Sto solo cercando un esempio funzionante che potrebbe fare snapshot con NO mostrando qualsiasi forma/frame - "senza testa". Come avviare l'app, richiede un'istantanea di qualsiasi html che passo senza mostrare alcuna finestra sullo schermo. Come fa PhantomJS. – ses

Problemi correlati