Generate Image or Thumbnail of a webpage using java

Long time ago in a project we had requirement to show image of a webpage on mouseover of link. I started looking for a pure java implementation for the same. After searching a lot I came to know that it is not feasible to generate image of a webpage using pure java.

Before some days back I came to know that this can be achieved easily through QT library, which is a  cross platform application and UI platform written in C++. QT library provides webkit engine to render webpages in their natural look and feel, so I decided to write my own JNI wrapper on top of QT thumbnail application. But after spending some time on my core c++ application I came to know about QT-Jambi, a java wrapper for QT library.

So I started with QT-Jambi and managed to write my own implementation of Thumbnailer application. Here I am sharing SiteGraphThumbnailerDemo program using the same. Have a look at code snippet below which describes key points in the Thumbnailer application. To save spaces I have removed import statements, constructors and getters-setters. Eager developers like me can directly jump to the Download link of whole source code at the end of this post.

QT Jambi provides QWebPage object which is a part of QT Webkit library.

protected QWebPage page;

As shown below makeSnap() method is used to load html content of a provided URL. QT-Jambi provides event based method invocation mechanism. In below method we have registered loadStarted(), loadProgress() and loadDone()method hooks for specifict implementation for these events.


   /**
	 * Method to load html content from provided url
	 */
	public boolean makeSnap(){
		try{
		if(logger.isDebugEnabled())
			logger.debug("Connecting to url : "+this.url);
		if(QApplication.instance() == null)
			QApplication.initialize(new String[] { });
		page = new QWebPage(null);
		page.mainFrame().load(new QNetworkRequest(this.url));
		logger.debug("Page Loaded");
		page.loadStarted.connect(this, "loadStarted()");
		page.loadProgress.connect(this, "loadProgress()");
		page.loadFinished.connect(this, "loadDone()");
		logger.debug("Load Finished");
		finished.connect(QApplication.instance(), "quit()");
		QApplication.exec();
    	}catch(Exception exp){
			logger.error(exp.getMessage()+ " Error While taking a snap");
			return false;
		}
		return true;
	}
Once the whole web page is rendered in QT Webkit engine loadDone() event is invoked internally and image processing can be completed using loaded webpage content. You can verify content loading start and content loading progress in loadStarted() and loadProgress() event hooks.
	private void loadStarted(){
		logger.debug("Part in Started");
	}
	private void loadProgress(){
		logger.debug("Part in Progress");
	}
Once image loading is completed QWebPage provides lots of customization on loaded content before exporting it to a full fledged image. It includes image scaling, transformations etc. Check QT-Jambi Javadoc for more information on QImage.
	/**
	 * Called internally by makeSnap() method to save loaded image(s) based on provided ImageAttribute details.
	 */
	private boolean loadDone() {
		logger.debug("Loading for page url : "+ this.url);
		for(ImageAttributes imageAttribute: this.imageAttributes){
			logger.debug("Loading for page url : "+ this.url);
			page.setViewportSize(imageAttribute.getImageSize());
			page.mainFrame().setScrollBarPolicy(Orientation.Horizontal, ScrollBarPolicy.ScrollBarAlwaysOff);
			page.mainFrame().setScrollBarPolicy(Orientation.Vertical, ScrollBarPolicy.ScrollBarAlwaysOff);
			page.setViewportSize(new QSize(Constants.DEFAULT_IMAGE_WIDTH, Constants.DEFAULT_IMAGE_HEIGHT));
		    QImage image = new QImage(page.viewportSize(), QImage.Format.Format_ARGB32);
		    image.fill(QColor.white.rgb());
		    QPainter painter = new QPainter(image);
		    page.mainFrame().render(painter);
		    painter.end();
		    String imageName= imageAttribute.getAbsoluteImageFilePath() + imageAttribute.getImageSuffix();
		    logger.debug("Preparing image : "+ imageName);
		    logger.info("Image prepared: "+image.save(imageName));
		}
	    finished.emit();
	    return true;
    }

You can download whole source code for this demo application from box.net.

Note that Apache Maven is used to resolve dependencies of this application. QT-Jambi dependencies can take some time to load with a slow internet connection as it’s total size is approx. 85MB.

Please add your suggestions/comments below.

UPDATE : Looks like number of people have downloaded above demo. Please provide your comments/suggestions below regarding the demo or post.

Added my first open source application on github

After so much of delay at last I have published my first open source application on GitHub.

As described in my previous post I have used qt-jambi to generate snapshot/thumbnail for given website using java. This application is developed in java and I have used Maven for dependency management and build tool. I will be adding several functionalities later on, as per my convenience.

I have named it SiteGraphThumbnailer have  a look @ it and provide your feedback if any.

Its opensource so you can modify it as per your requirement.

Is it too late to implement

While working on one of the project I was unable to find any open source Java implementation to generate website thumbnails. At that time I have decided to write my own code to do the same. As this was not possible purely with Java only I get back to C/C++ implementation and found CutyCapt C++ webkit based image rendering utility developed using QT Library. Though it was written in C++ only that’s what I wanted. I decided to write my own Java wrapper on top of CutyCapt to extend its functionality in Java.

I found pretty useful Java bindings for QT Library called QT-Jambi and created my prototype using it. But just before I am writing this post I decided to give name to it as I already had prototype ready with me based on qt-jambi library in Java and is working fine.

Before giving a name to this project I decided to make another broaden search about similar projects available in the community. I was surprise to see that what exactly I was thinking to make including extensions and rich functionality along with simple utility was already available.

Damn . . .

So what should I do now? I should scrap my efforts on this project? As I don’t want to reinvent the wheel again.

But wait let me rethink on it and I may able to provide more functionality than existing projects. After publishing my code on one of the source code hosting services I will post my prototype on my blog.