Создать эскиз веб-сайта?

Для моего приложения мне нужно динамически создавать эскизы веб-сайтов. Пока у меня этот код из 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);
    }


}

Но, как вы можете видеть здесь, я не знаю, какую часть браузера я должен передать методу захвата. Любые подсказки?

Ответ 1

Я не вижу, как код, который вы предоставили, может работать. 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-решением, чтобы выйти из экрана. Я считаю, что связанный вопрос может помочь вам в дальнейшем.

Ответ 2

Насколько я знаю, когда вы используете объект Browser, загружаемая вами веб-страница отображается непосредственно на объект Composite, который вы передаете ему через конструктор. В вашем случае он отображается в элементе Shell, который является объектом в стиле окна. Не существует способа отображения веб-страницы непосредственно, скажем, объекта изображения.

Однако вы можете попробовать создать экземпляр вашего браузера на объекте Canvas и сохранить изображение прямо оттуда.

К сожалению, я не могу проверить, работает ли это или нет, потому что у меня нет Eclipse или SWT; Я уверен, однако, что, если то, что вы хотите сделать, выполнимо, это единственный способ.

Ответ 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 имеет метод print, который принимает GC, который может рисовать, включая изображение и другие интересные нам материалы, в документации говорится: "Класс GC - это место, где расположены все возможности рисования, которые поддерживаются SWT. нарисуйте либо изображение, либо элемент управления, либо непосредственно на дисплее.".

Однако в этот конкретный момент мне непонятно, как точно заставить его делать то, что я хочу. В любом случае я поднимаю этот момент, чтобы вы знали. Мне все еще нужно заглядывать в нее дальше.

Ответ 4

Может быть, вам лучше сделать страницу за кадром с самого начала. Для такой задачи вы можете, например, использовать "летающую тарелку" (которая является только xhtml, поэтому вам нужно привести в порядок). Похоже, что есть некоторые инструменты для интерфейса Webkit непосредственно с Java.