生成网站缩略图?

时间:2012-05-01 16:51:25

标签: java swt

对于我的应用程序,我需要动态创建网站的缩略图。到目前为止,我有来自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);
    }


}

但正如你在这里看到的,我不知道我应该将哪一部分浏览器传递给我的捕获方法。任何提示?

4 个答案:

答案 0 :(得分:10)

我没有看到,您提供的代码如何工作。 Shell未打开,没有大小,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();
   }

}

但有一些严重的警告:

  • 你无法在屏幕外执行此操作。 SWT截图只是当前显示的副本。
  • 截取屏幕时,包含浏览器的窗口必须位于顶部。
  • 在onLoad之后页面应该是可见的(google.com实际上并非如此,但是因为asyncExec调用而对我有效 - 如果你得到一张白色图片,请尝试其他网址)
  • 结果取决于您的操作系统及其安装的浏览器

我会使用非Java解决方案,以便离开屏幕绘图。我相信相关问题可能会帮助您进一步发展。

答案 1 :(得分:4)

据我所知,当您使用Browser对象时,您加载的网页将直接呈现在您通过构造函数传递给它的Composite对象上。在您的情况下,它将在您的Shell项目上呈现,这是一个窗口样式的对象。没有方法直接在图像对象上呈现网页。

但是,您可以尝试在Canvas对象上实例化浏览器并直接从那里保存图像。

不幸的是我无法测试这是否有效,因为我既没有安装Eclipse也没有安装SWT;我很确定,如果你想做的事情是可行的,这是唯一的方法。

答案 2 :(得分:3)

我自己做了一些实验。我的直觉是尝试JEditorPane就像提到的那样in the answer your code is based on.我不知道它会有多大的帮助,但它可能有所帮助。我给出了一些结果,但是由于显而易见的原因,JEditorPane中的css支持等运气看起来很丑陋。

这是我的代码:

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

我也对SWT进行了一些挖掘,我发现有些人认为可能有用,但由于我现在运气好,所以无法测试。根据我的阅读,我必须同意@Emanuele Bezzi(+1),我们将不得不以某种方式使用Shell来获取网站的内容,我们实际上只对其感兴趣。

我发现Shellprint方法,它可以将GC对象包含在Image中,包括对Image和其他有趣的东西,文档说:“Class GC是SWT支持的所有绘图功能所在的位置。实例用于在图像,控件或直接在人机界面上绘图。“

然而在这个特殊的时刻,我不清楚如何让它完全按照我的意愿去做。无论如何,我提出这一点只是为了让你知道。我还需要进一步研究。

答案 3 :(得分:2)

也许你最好从一开始就在屏幕外渲染页面。对于这样的任务,您可以使用“飞碟”(仅限xhtml,因此您需要整理)。似乎还有一些工具可以直接从Java接口Webkit。