2012-05-01 6 views
10

Per la mia applicazione ho bisogno di creare dinamicamente miniature di siti web. Finora ho questo codice da SO:Genera una miniatura del sito web?

public class CreateWebsiteThumbnail { 

    private static final int WIDTH = 128; 
    private static final int HEIGHT = 128; 

    private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); 

    public void capture(Component component) { 
     component.setSize(image.getWidth(), image.getHeight()); 

     Graphics2D g = image.createGraphics(); 
     try { 
       component.paint(g); 
     } finally { 
       g.dispose(); 
     } 
    } 

    private BufferedImage getScaledImage(int width, int height) { 
     BufferedImage buffer = new BufferedImage(width, height, 
         BufferedImage.TYPE_INT_RGB); 
     Graphics2D g = buffer.createGraphics(); 
     try { 
       g.drawImage(image, 0, 0, width, height, null); 
     } finally { 
       g.dispose(); 
     } 
     return buffer; 
    } 

    public void save(File png, int width, int height) throws IOException { 
     ImageIO.write(getScaledImage(width, height), "png", png); 
    } 

    public static void main(String[] args) throws IOException { 

     Shell shell = new Shell(); 
     Browser browser = new Browser(shell, SWT.EMBEDDED); 
     browser.setUrl("http://www.google.com"); 


     CreateWebsiteThumbnail cap = new CreateWebsiteThumbnail(); 
     cap.capture(What her?); 
     cap.save(new File("foo.png"), 64, 64); 
    } 


} 

Ma, come potete vedere qui, non so quale parte del browser devo passare al mio metodo di cattura. Qualche suggerimento?

+0

Si otterrà una miniatura distorta a meno che non si calcoli la larghezza e l'altezza della miniatura in modo proporzionale alla larghezza e all'altezza dell'immagine del sito Web. –

+0

@GilbertLeBlanc per ora sarei felice se ottengo qualche miniatura – RoflcoptrException

+0

stavo per aspettare e vedere se qualcuno ha una risposta, ma per quanto posso dire, la classe Browser non ha alcun metodo per ottenere l'immagine del web pagina. Se stavi usando Swing, ti suggerirei di usare la classe Robot per ottenere l'immagine. –

risposta

10

Non vedo, come potrebbe funzionare il codice che hai fornito. Ilnon è aperto, non ha il tempo di caricare nulla, nessun ciclo di eventi sembra essere in esecuzione per abilitare qualsiasi disegno, ...

Il seguente codice fa uno screenshot di un pagina utilizzando il browser SWT:

import java.io.IOException; 

import org.eclipse.swt.SWT; 
import org.eclipse.swt.browser.Browser; 
import org.eclipse.swt.browser.ProgressEvent; 
import org.eclipse.swt.browser.ProgressListener; 
import org.eclipse.swt.graphics.GC; 
import org.eclipse.swt.graphics.Image; 
import org.eclipse.swt.graphics.ImageData; 
import org.eclipse.swt.graphics.ImageLoader; 
import org.eclipse.swt.layout.FillLayout; 
import org.eclipse.swt.widgets.Display; 
import org.eclipse.swt.widgets.Shell; 


public class CreateWebsiteThumbnail { 

    private static final int WIDTH = 800; 
    private static final int HEIGHT = 600; 


    public static void main(String[] args) throws IOException { 
     final Display display = new Display(); 
     final Shell shell = new Shell(); 
     shell.setLayout(new FillLayout()); 
     final Browser browser = new Browser(shell, SWT.EMBEDDED); 
     browser.addProgressListener(new ProgressListener() { 

     @Override 
     public void changed(ProgressEvent event) {} 

     @Override 
     public void completed(ProgressEvent event) { 
      shell.forceActive(); 
      display.asyncExec(new Runnable() { 

       @Override 
       public void run() { 
        grab(display, shell, browser); 
       } 
      }); 

     } 
     }); 
     browser.setUrl("http://www.google.com"); 

     shell.setSize(WIDTH, HEIGHT); 
     shell.open(); 

     while (!shell.isDisposed()) { 
     if (!display.readAndDispatch()) display.sleep(); 
     } 
     display.dispose(); 
    } 

    private static void grab(final Display display, final Shell shell, final Browser browser) { 
     final Image image = new Image(display, browser.getBounds()); 
     GC gc = new GC(browser); 
     gc.copyArea(image, 0, 0); 
     gc.dispose(); 

     ImageLoader loader = new ImageLoader(); 
     loader.data = new ImageData[] { image.getImageData() }; 
     loader.save("foo.png", SWT.IMAGE_PNG); 
     image.dispose(); 

     shell.dispose(); 
    } 

} 

Ma ci sono alcuni avvertimenti gravi:

  • non si può fare questo fuori dallo schermo.Gli screenshot SWT sono solo una copia del display corrente.
  • La finestra contenente il browser deve essere in primo piano, quando si acquisisce lo screenshot.
  • la pagina deve essere visibile dopo onLoad (che in realtà non è il caso di google.com, ma funziona per me a causa della chiamata asyncExec in ogni caso - se si ottiene un'immagine bianca, provare un altro URL)
  • Il risultato è dipende dal tuo sistema operativo e dai suoi browser installati

Mi piacerebbe andare con una soluzione non Java, al fine di ottenere fuori disegno schermo. Credo che la domanda collegata possa aiutarti ad andare oltre.

+0

I ragazzi non aggiungerebbero un 'PaintListener' all'oggetto' Shall', dove si farebbe il disegno su un'immagine, lavorare in questa situazione? Qualcosa come in questo tutorial di pittura per 'SWT', http://zetcode.com/tutorials/javaswttutorial/painting/ – Boro

+0

Grazie, questo sembra esattamente quello che sto cercando. Tuttavia, ottengo sempre un'immagine vuota (solo lo sfondo predefinito). Ciò accade anche se non eseguo il rendering offscreen. Cioè il browser è sempre visibile. – RoflcoptrException

+0

@ the.duckmann per notificare il commento precedente;) – RoflcoptrException

4

Per quanto ne so, quando si utilizza un oggetto Browser, la pagina Web caricata viene visualizzata direttamente sull'oggetto Composito che si passa attraverso il costruttore. Nel tuo caso, viene reso sul tuo oggetto Shell che è un oggetto in stile finestra. Non esiste un metodo per rendere la pagina web direttamente su, ad esempio, un oggetto Immagine.

Si può provare, tuttavia, per istanziare il browser su un oggetto Canvas e salvare l'immagine direttamente da lì.

Purtroppo non riesco a verificare se questo funziona o no perché non ho né Eclipse né SWT installato; Sono abbastanza sicuro che, se quello che vuoi fare è fattibile, questo è l'unico modo.

3

Ho fatto qualche esperimento da solo. La mia intuizione è stata quella di provare su JEditorPane proprio come detto in the answer your code is based on. Non so di quanto aiuto possa essere, ma potrebbe essere d'aiuto. Fornisco alcuni risultati, ma per ovvi motivi, la fortuna del supporto css ecc in JEditorPane sembra tutto brutto.

Questo è il mio codice:

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.Graphics2D; 
import java.awt.event.ActionEvent; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import java.net.URL; 
import javax.imageio.ImageIO; 
import javax.swing.*; 
import javax.swing.text.html.HTMLEditorKit; 

public class WebPageToImageThumbnail { 

    public static void main(String[] a) throws Exception { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       JFrame frame = new JFrame(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       final JEditorPane editorPane = new JEditorPane(); 
       editorPane.setEditorKit(new HTMLEditorKit()); 
       try { 
        editorPane.setPage(new URL("http://weblogs.java.net/blog/alex2d/archive/2008/12/jwebpane_projec.html")); 
       } catch (IOException ex) { 
       } 
       final JPanel panel = new JPanel(new BorderLayout()); 
       panel.add(new JScrollPane(editorPane), BorderLayout.CENTER); 
       panel.add(new JButton(new AbstractAction("SAVE") { 
        @Override 
        public void actionPerformed(ActionEvent e) { 
         BufferedImage image = capture(editorPane); 
         try { 
          save(image, new File("foo.png"), 64, 64); 
         } catch (IOException ex) { 
         } 
        } 
       }), BorderLayout.SOUTH); 
       frame.setContentPane(panel); 
       frame.setSize(600, 400); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public static BufferedImage capture(Component component) { 
     BufferedImage image = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_RGB);//component.setSize(image.getWidth(), image.getHeight()); 
     Graphics2D g = image.createGraphics(); 
     try { 
      component.paint(g); 
     } finally { 
      g.dispose(); 
     } 
     return image; 
    } 

    private static BufferedImage getScaledImage(BufferedImage image, int width, int height) { 
     BufferedImage buffer = new BufferedImage(width, height, 
       BufferedImage.TYPE_INT_RGB); 
     Graphics2D g = buffer.createGraphics(); 
     try { 
      g.drawImage(image, 0, 0, width, height, null); 
     } finally { 
      g.dispose(); 
     } 
     return buffer; 
    } 

    public static void save(BufferedImage image, File png, int width, int height) throws IOException { 
     ImageIO.write(getScaledImage(image, width, height), "png", png); 
    } 
} 

Ho anche fatto un po 'scavare sulla SWT ho trovato alcuni pensa che potrebbe essere utile, ma dal momento che attualmente il tempo di fortuna, non posso provare. Da quanto ho letto, devo concordare con @Emanuele Bezzi (+1) che dovremo utilizzare la Shell in qualche modo per ottenere il contenuto del sito, in cui siamo effettivamente interessati solo.

ho scoperto che Shell ha print metodo che prende GC oggetto che può dipingere tra cui all'Immagine e altro interessante per noi roba, la documentazione dice: "Classe GC è dove tutte le funzionalità di disegno che sono supportati da SWT sono localizzato. Le istanze vengono utilizzate per disegnare su un'immagine, un controllo o direttamente su un display. ".

Eppure in questo particolare momento non mi è chiaro come ottenere esattamente ciò che voglio. Ad ogni modo, sto sollevando questo punto solo per renderti consapevole. Ho ancora bisogno di esaminarlo ulteriormente.

2

Forse è meglio rendere la pagina non in linea fin dall'inizio. Ad esempio, per esempio, puoi usare "disco volante" (che è solo xhtml, quindi devi riordinare). Sembra che ci siano anche alcuni strumenti per interfacciare Webkit direttamente da Java.