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?
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:
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With