Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate thumbnail of website?

Tags:

java

swt

For my application I need to dynamically create thumbnails of websites. So far I have this code from SO:

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);
    }


}

But as you can see here, I don't know which part of the browser I should pass to my capture method. Any hints?

like image 451
RoflcoptrException Avatar asked May 01 '12 16:05

RoflcoptrException


3 Answers

I don't see, how the code you provided could work. The Shell is not opened, it has no size, the Browser didn't get time to actually load anything, no event loop seems to be running to enable any drawing, ...

The following code does a screenshot of a page using SWT browser:

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();
   }

}

But there are some serious caveats:

  • You cannot do this off-screen. SWT screenshots are just a copy of the current Display.
  • The window containing your browser must be on top, when taking the screenshot.
  • The page should be visible after onLoad (which is actually not the case with google.com, but works for me because of the asyncExec call anyway - if you get a white image, try another URL)
  • The result is dependant on your OS and its installed browsers

I'd go with a non Java-solution, in order to get off screen drawing. I believe the linked question might help you to get further.

like image 148
the.duckman Avatar answered Oct 10 '22 23:10

the.duckman


As far as I know, when you use a Browser object, the webpage you load is rendered directly on the Composite object you pass to it through the constructor. In your case, it is rendered on your Shell item which is a window-style object. There is no method to render the webpage directly on, say, an Image object.

You can try, though, to instantiate your Browser on a Canvas object and save the image directly from there.

Unfortunately I am unable to test whether this works or not because I have neither Eclipse nor SWT installed; I am pretty sure though that, if what you want to do is doable, this is the only way.

like image 44
Emanuele Bezzi Avatar answered Oct 11 '22 00:10

Emanuele Bezzi


I did some experimenting myself. My intuition was to try on JEditorPane just like mentioned in the answer your code is based on. I do not know of how much help it is going to be but it might help. I gives some results, but from obvious reasons, luck of css support etc in JEditorPane it all looks ugly.

This is my code:

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);
    }
}

I also did some digging about the SWT I found some thinks that might be of use, but since I currently luck time, I cannot test. From what I read I have to agree with @Emanuele Bezzi (+1) that we are going to have to use the Shell somehow to get the content of the site, in which we are effectively only interested.

I found out that Shell has print method which takes GC object which can paint including to Image and other interesting to us stuff, the documentation says: "Class GC is where all of the drawing capabilities that are supported by SWT are located. Instances are used to draw on either an Image, a Control, or directly on a Display.".

Yet at this particular moment it is not clear to me how to exactly get it to do what I want. Anyway I am raising this point just to make you aware. I still need to look into it further.

like image 44
Boro Avatar answered Oct 10 '22 23:10

Boro