Javaでグーグルマップ

 GoogleMapのSWTウィジットで『Google Maps Widgets』というのをみつけた。
 ちょっとおもしろいと思ったので、勉強がてら、SWTのBrowserウィジットにGoogleMapを表示して、指定範囲の緯度・経度とその画像を取得するプログラムを書いてみる。
 ■準備
 ①GoogleMapの登録をする。
 ②SWTを準備する。

 ■ソースコード
 とりあえず、次のようなコードを書いてみた。
 あと、JavaScriptのオブジェクトを直接に操作できなさそう?だったので、GoogleMapで取得した緯度・経度はステータスバーに書き込み、StatusTextListenerで文字列として取得している。

package test;

import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.ProgressAdapter;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.StatusTextEvent;
import org.eclipse.swt.browser.StatusTextListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;

public class GoogleMapTest {
	private Display display;
	private final Shell shell;
	private Point pos=null,pos2=null;
	private Browser browser;
	private Timer timer;
	private String posMes;
	private StatusTextListener listener;
	private BufferedImage img;
	
	public GoogleMapTest(){
		display = new Display();
		shell = new Shell(display);
		shell.setLayout(new FillLayout());
		shell.setText("GoogleMap");
		browser = new Browser(shell, SWT.NONE);
		browser.setUrl("GoogleMapを登録したファイルのURL");
		browser.setLayout(new FillLayout());
		timer=new Timer();
		ProgressAdapter pa=new ProgressAdapter(){
			final ProgressAdapter px=this;
			@Override
			public void completed(ProgressEvent arg0) {
				TimerTask task=new TimerTask(){
					@Override
					public void run() {
						Runnable rr=new Runnable(){
							@Override
							public void run() {
								browser.execute(
									"if (GBrowserIsCompatible()) {" +
									"var map = new GMap2(document.getElementById(\"map\"));" +
									"map.setCenter(new GLatLng(34.6833333333333, 135.50), 7);" +
									"map.addControl(new GLargeMapControl());" +
									"map.addControl(new GMapTypeControl());" +
									"map.enableContinuousZoom();"+
									"map.enableScrollWheelZoom()}");
								timer.cancel();
								browser.removeProgressListener(px);
							}
						};
						shell.getDisplay().syncExec(rr);
					}
				};
				timer.schedule(task, 1000);
			}
		};
		browser.addProgressListener(pa);
		listener = new StatusTextListener() {
			public void changed(StatusTextEvent event) {
				posMes=event.text;
				if(posMes.isEmpty()){
					browser.execute("map.clearOverlays();");
					return;
				}
				browser.removeStatusTextListener(this);
				Runnable rr=new Runnable(){
					public void run(){
						MessageBox box = new MessageBox(shell,SWT.OK|SWT.CANCEL);
						box.setMessage("O.K.?");
						int result = box.open();
						if(result==SWT.OK){
							MessageBox mes = new MessageBox(shell,SWT.OK);
							mes.setMessage(posMes);
							mes.open();
							FileDialog saveDialog = new FileDialog(shell,SWT.SAVE);
							String saveFile = saveDialog.open();
							File f=new File(saveFile);
							try{
								ImageIO.write(img, "png", f);
							}catch(IOException e){}
							display.syncExec(new Runnable(){public void run(){shell.dispose();}});
						}else{
							display.syncExec(new Runnable(){public void run(){
								browser.removeStatusTextListener(listener);
							}});
						}
					}
				};
				display.syncExec(rr);
			}
		};
		browser.addMouseListener(new MouseListener(){
			@Override
			public void mouseDoubleClick(MouseEvent arg0) {}
			@Override
			public void mouseDown(MouseEvent arg0) {}
			@Override
			public void mouseUp(MouseEvent arg0) {
				if(arg0.button==3){
					if(pos==null){
						pos=new Point(arg0.x,arg0.y);
					}else{
						browser.addStatusTextListener(listener);
						int[] px=new int[4];
						pos2=new Point(arg0.x,arg0.y);
						if(pos.x<pos2.x){
							px[0]=pos.x;px[1]=pos2.x;
						}else{
							px[1]=pos.x;px[0]=pos2.x;
						}
						if(pos.y>pos2.y){
							px[2]=pos.y;px[3]=pos2.y;
						}else{
							px[3]=pos.y;px[2]=pos2.y;
						}
						img=processImage();
						browser.execute(
							 "lang0=map.fromContainerPixelToLatLng(new GPoint("+
							 Integer.toString(px[0])+","+Integer.toString(px[2])+"));"+
							 "lang1=map.fromContainerPixelToLatLng(new GPoint("+
							 Integer.toString(px[1])+","+Integer.toString(px[3])+"));"+
							 "window.status=lang0+'_'+lang1");
						pos=null;
					}
				}
			}
		});
		browser.addMouseMoveListener(new MouseMoveListener(){
			@Override
			public void mouseMove(MouseEvent arg0) {
				if(pos!=null){
					int[] px=new int[4];
					pos2=new Point(arg0.x,arg0.y);
					if(pos.x<pos2.x){
						px[0]=pos.x;px[1]=pos2.x;
					}else{
						px[1]=pos.x;px[0]=pos2.x;
					}
					if(pos.y<pos2.y){
						px[2]=pos.y;px[3]=pos2.y;
					}else{
						px[3]=pos.y;px[2]=pos2.y;
					}
					String[] pixel=new String[]{
						"map.fromContainerPixelToLatLng(new GPoint("+
						Integer.toString(px[0])+","+Integer.toString(px[2])+"))",
						"map.fromContainerPixelToLatLng(new GPoint("+
						Integer.toString(px[1])+","+Integer.toString(px[2])+"))",
						"map.fromContainerPixelToLatLng(new GPoint("+
						Integer.toString(px[1])+","+Integer.toString(px[3])+"))",
						"map.fromContainerPixelToLatLng(new GPoint("+
						Integer.toString(px[0])+","+Integer.toString(px[3])+"))",
						"map.fromContainerPixelToLatLng(new GPoint("+
						Integer.toString(px[0])+","+Integer.toString(px[2])+"))"};
					browser.execute(
						"map.clearOverlays();var points = [];points[0]="+pixel[0]+";"+
						"points[1] ="+pixel[1]+";points[2] ="+pixel[2]+";"+
						"points[3] ="+pixel[3]+";points[4] ="+pixel[4]+";"+
						"var polyline = new GPolyline(points);map.addOverlay(polyline);");
				}
			}
		});
		shell.setMaximized(true);
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}

	private BufferedImage processImage(){
		final GC gc = new GC(browser);
		Rectangle rect = shell.getClientArea();
		Image img = new Image(display, rect.width, rect.height);
		gc.copyArea(img, 0, 0);
		BufferedImage bimg = swt2awt(img.getImageData());
		return bimg;
	}
	
	private BufferedImage swt2awt(ImageData data){
		ColorModel colorModel = null;
		PaletteData palette = data.palette;
		if (palette.isDirect) {
			colorModel = new DirectColorModel(data.depth, palette.redMask,
					palette.greenMask, palette.blueMask);
			BufferedImage bufferedImage = new BufferedImage(colorModel,
					colorModel.createCompatibleWritableRaster(data.width,
							data.height), false, null);
			WritableRaster raster = bufferedImage.getRaster();
			int[] pixelArray = new int[3];
			for (int y = 0; y < data.height; y++) {
				for (int x = 0; x < data.width; x++) {
					int pixel = data.getPixel(x, y);
					RGB rgb = palette.getRGB(pixel);
					pixelArray[0] = rgb.red;
					pixelArray[1] = rgb.green;
					pixelArray[2] = rgb.blue;
					raster.setPixels(x, y, 1, 1, pixelArray);
				}
			}
			return bufferedImage;
		} else {
			RGB[] rgbs = palette.getRGBs();
			byte[] red = new byte[rgbs.length];
			byte[] green = new byte[rgbs.length];
			byte[] blue = new byte[rgbs.length];
			for (int i = 0; i < rgbs.length; i++) {
				RGB rgb = rgbs[i];
				red[i] = (byte) rgb.red;
				green[i] = (byte) rgb.green;
				blue[i] = (byte) rgb.blue;
			}
			if (data.transparentPixel != -1) {
				colorModel = new IndexColorModel(data.depth, rgbs.length, red,
						green, blue, data.transparentPixel);
			} else {
				colorModel = new IndexColorModel(data.depth, rgbs.length, red,
						green, blue);
			}
			BufferedImage bufferedImage = new BufferedImage(colorModel,
					colorModel.createCompatibleWritableRaster(data.width,
							data.height), false, null);
			WritableRaster raster = bufferedImage.getRaster();
			int[] pixelArray = new int[1];
			for (int y = 0; y < data.height; y++) {
				for (int x = 0; x < data.width; x++) {
					int pixel = data.getPixel(x, y);
					pixelArray[0] = pixel;
					raster.setPixel(x, y, pixelArray);
				}
			}
			return bufferedImage;
		}
	}
	
	public static void main(String[] args){
		GoogleMapTest gm=new GoogleMapTest();
	}
}

 ■結果
 指定範囲の緯度、経度とその画像が取得できた。
 なにか使い道がありそう。