lobobrowser cobraを使ってWEBのスクリーンショットを撮る

web2jpg.jar -a 0.5625 "http://www.google.co.jp" "sshot.jpg"


な感じ


jarとライブラリとソース
http://sorr.biz/spinouts/web2jpg.zip


オプション

  • a アスペクト比
  • cw キャプチャする(大体の)横幅
  • tw jpgの横幅
  • d キャプチャするまでのdelay


左上に小さくウィンドウが一瞬出てしまうのがウザいが、出さずにうまくやる方法がわからなかった
レンダリングの完了を知る方法もわからず…というか手を入れるのが大変そうだったので適当なdelay後にキャプチャすることにした


ブラウザとしての再現性には難がある
特にCSSは厳密に解釈するだとかで全然まともに動かない
jsも文字コード周りでよく死ぬっぽい
しかしものすごく簡単にこんなことができるので、もちっとパーサとレンダラの精度が上がってくるとマジで実用になりそう

package biz.sorr.web2jpg;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.logging.*;

import javax.imageio.ImageIO;
import javax.swing.*;

import org.lobobrowser.html.gui.*;
import org.lobobrowser.html.test.*;

public class Web2jpg {
	private String uri;
	private String filename;
	private int captureWidth;
	private int captureHeight;
	private int thumbWidth;
	private int thumbHeight;
	private double aspectRate;
	private int delay;
	
	private JFrame window;
	private HtmlPanel panel;
	
	public static void main(String[] args) {
		new Web2jpg(args);
	}
	Web2jpg(String[] args){
		argProcess(args);
		
		if(null == uri) return;
		if(null == filename) return;
		
		if(aspectRate <= 0){
			aspectRate = 0.75;
		}
		if(captureWidth <= 0){
			captureWidth = 800;
		}
		if(thumbWidth <= 0){
			thumbWidth = 240;
		}
		if(delay <= 0){
			delay = 5000;
		}
		captureHeight = (int)(captureWidth * aspectRate);
		thumbHeight   = (int)(thumbWidth * aspectRate);
		
		System.out.println("uri->" + uri);
		System.out.println("filename->" + filename);
		System.out.println("acpectRate->"    + aspectRate);
		System.out.println("captureWidth->"  + captureWidth);
		System.out.println("captureHeight->" + captureHeight);
		System.out.println("thumbWidth->"    + thumbWidth);
		System.out.println("thumbHeight->"   + thumbHeight);
		System.out.println("delay->"         + delay);

		try{
			
			Logger.getLogger("org.lobobrowser")
			.setLevel(Level.WARNING);
			
			
			window = new JFrame();
			window.setVisible(true);
		    window.setVisible(false);
			
			panel  = new HtmlPanel();
		    window.getContentPane().add(panel);
		    window.setSize(captureWidth, captureHeight);

		    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		    
		    
		    new SimpleHtmlRendererContext(panel, new SimpleUserAgentContext())
					.navigate(uri);

		}catch(Exception ex){
			ex.printStackTrace();
		}
		
		
		DummyWait dw = new DummyWait();
		Thread dummyWait = new Thread(dw); 
		
		dummyWait.start();
		
		try {
			dummyWait.join();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		
	}
	private void Capture(){
		System.out.println("Capture()");
        try {
        	
        	BufferedImage image = 
            		new BufferedImage( panel.getWidth(), panel.getHeight(),
            				BufferedImage.TYPE_INT_RGB );
            BufferedImage thumb = 
            		new BufferedImage(thumbWidth, thumbHeight,
	                    		BufferedImage.TYPE_INT_RGB );
            Graphics2D g2d = image.createGraphics();
            panel.paint(g2d);
            
            //http://yusuke.homeip.net/diary/2006/02/09/1139476974993.html
            g2d = thumb.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
    		RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
    		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    		RenderingHints.VALUE_ANTIALIAS_ON);
    		g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
    		RenderingHints.VALUE_COLOR_RENDER_QUALITY);
    		g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
    		RenderingHints.VALUE_DITHER_ENABLE);
    		g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
    		RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    		g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
    		RenderingHints.VALUE_RENDER_QUALITY);
    		g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
    		RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    		g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
    		RenderingHints.VALUE_FRACTIONALMETRICS_ON);
    		g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
    		RenderingHints.VALUE_STROKE_NORMALIZE);
    		g2d.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);

            g2d.dispose();
            
            ImageIO.write( thumb, "jpeg", new File( filename ) );

        } catch ( Exception ex) {
        	ex.printStackTrace();
        }
	}
	private class DummyWait implements Runnable {
		public void run() {
			try {
				Thread.sleep(delay);
			} catch (InterruptedException e) {
				System.out.println(e);
			}
			Capture();
			window.dispose();
		}
	}
	private void argProcess(String[] args){
		String id;
		String val; 
		for(int i = 0, i_n = args.length; i < i_n; i++){
		
			id = args[i];
			if('-' == id.charAt(0)){
				if(i == args.length - 1)
					break;
				
				val = args[i+1];
				if(id.equals("-a") || id.equals("-A")){
					try{
						aspectRate = Double.parseDouble(val); 
					}catch(Exception ex){
						System.out.println("invalid value->" + id);
						ex.printStackTrace();
					}
				}else if(id.equals("-cw")){
					int a = Integer.getInteger(val, 0);
					if(0 != a){
						captureWidth = a;
					}else{
						System.out.println("invalid value->" + id);
					}
					
				}else if(id.equals("-tw")){
					int a = Integer.getInteger(val, 0);
					if(0 != a){
						thumbWidth = a;
					}else{
						System.out.println("invalid value->" + id);
					}
				}else if(id.equals("-d") || id.equals("-D")){
					int a = Integer.getInteger(val, 0);
					if(0 != a){
						delay = a;
					}else{
						System.out.println("invalid value->" + id);
					}
				}
				i++;
			}else{
				if(null != filename){
					System.out.println("invalid argument(too many)->" + id);
				}
				if(null == uri){
					uri = id;
				}else{
					filename = id;
				}
			}
		}
	}
}