10

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

4 回答 4

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 调用对我有用——如果你得到一个白色图像,请尝试另一个 URL)
  • 结果取决于您的操作系统及其安装的浏览器

我会使用非 Java 解决方案,以便摆脱屏幕绘图。我相信链接的问题可能会帮助您走得更远。

于 2012-05-05T16:40:05.570 回答
4

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

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

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

于 2012-05-01T19:15:38.177 回答
3

我自己做了一些实验。我的直觉是尝试JEditorPane就像您的代码所基于的答案中提到的那样。我不知道它会有多少帮助,但它可能会有所帮助。我给出了一些结果,但由于显而易见的原因,css 支持等的运气JEditorPane看起来都很丑陋。

这是我的代码:

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 和其他我们感兴趣的东西,文档说:“类 GC 是 SWT 支持的所有绘图功能所在的位置。实例用于在图像、控件或直接在显示器上绘制。” .

然而,在这个特定的时刻,我不清楚如何让它做我想做的事。无论如何,我提出这一点只是为了让你知道。我还需要进一步研究。

于 2012-05-04T15:32:43.193 回答
2

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

于 2012-05-04T15:33:10.823 回答