Google Maps Static API v2を使ってみた

Google Maps Static API v2を使ってみた。

Maps Static APIは、地図の画像を画像ファイルとして取得するためのAPIだ。

昔、古いAPIでStatic APIをちょっとだけ使っていた。API v1の時代だ。
しかし、2009年に終了してしまっていて、今では旧APIを叩いても地図の画像を得られない。

先日のGeolocation APIのときと同様にAPI Keyを新しく取得する必要がある。
(旧API KeyをAPI v2に適用しようとしても弾かれてしまう)
Maps Static API v2 Upgrade Guide  –  Maps Static API  –  Google Developers

簡単にAPI v2を試す方法は、ブラウザで次のようにURLを入力してやればよい。

https://maps.googleapis.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=13&size=600x300&maptype=roadmap&markers=color:blue%7Clabel:S%7C40.702147,-74.015794&markers=color:green%7Clabel:G%7C40.711614,-74.012318&markers=color:red%7Clabel:C%7C40.718217,-73.998284&key=自分のキーをここに書く

結果、ブラウザの画面に地図の画像ファイルが表示される。

wgetコマンドやcurlコマンドを使ってAPIを叩くことで画像のファイルを直接保存することも可能だ。
(httpsでアクセスしているのだが、httpでURLを指定しても動作する。)

libcurlを使って自作プログラムの中から地図の画像ファイルを取得するのも可能だが、ファイルを取得するだけのためにちょっと大がかりなライブラリを使うのは大げさかもしれない。
なので、自分はwgetっぽい動作をするプログラムをWinsockライブラリを使って作っていた。(Windows上で)

API v2で、地図の画像を取得するプログラムのソースコードは、このようになる。(C言語)

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <winsock.h>
#include "google_maps_api_key.h"

int get_sv_name(char *url_string,char *result)
{
	char url[1024],server[1024];
	int i,j,pos,pos2;
	
	for (i=0;i<strlen(url_string);i++) { url[i]=tolower(url_string[i]); }// to lower case
	
	//http文字列を探す
	if ((url[0]=='h')&&(url[1]=='t')&&(url[2]=='t')&&(url[3]=='p')) {
		if (url[4]==':') {
			if (url[5]=='/') {
				if (url[6]=='/') {
					if (url[7]=='/') { pos=8; }//  "http:///" (wrong, but accept)
					else             { pos=7; }//  "http://" (correct case)
				} else {
					pos=6; //  "http:/" (wrong, but accept)
				}
			} else {
				pos=5; //  "http:" (wrong, but accept)
			}
		}  else if (url[4]=='/') {
			if (url[5]=='/') { pos=6; }//  "http//" (wrong, but accept)
			else             { pos=5; }//  "http/" (wrong, but accept)
		} else {
			pos=0; // cannot accept
		}
	} else if ((url[0]=='t')&&(url[1]=='t')&&(url[2]=='p')) {
		if (url[3]==':') {
			if (url[4]=='/') {
				if (url[5]=='/') {
					if (url[6]=='/') { pos=7; }//  "ttp:///"
					else             { pos=6; }//  "ttp://"
				} else {
					pos=5; //  "ttp:/"
				}
			} else {
				pos=4; //  "ttp:"
			}
		}  else if (url[3]=='/') {
			if (url[4]=='/') { pos=5; }//  "ttp//"
			else             { pos=4; }//  "ttp/"
		} else {
			pos=0; // cannot accept
		}
	}
	
	// get server name ("http://" is removed)
	j=0;
	for (i=pos;i<strlen(url);i++) {
		if ( url[i]=='/' ) { break; }
		result[j]=url[i]; result[j+1]='\0'; j++;
	}
	pos2=i; // end position of server name
	
	return pos2;
}

int Wget_file(char *savefile,char *request_URL)
{
	int i,l,sep,ret,soc,port,buf_len;
	WORD version;
	WSADATA wsaData;
	char svName[1024],reqPage[1024];
	char sendbuf[1024],recvbuf[1024];
	unsigned long sv_addr;
	struct hostent *host1;
	struct sockaddr_in server1;
	FILE *fp;
	
	version = MAKEWORD(1,1);
	ret = WSAStartup(version, &wsaData);
	if (ret != 0) { return -1; } // error, winsock init fail
	soc = socket(PF_INET,SOCK_STREAM,0);
	if (soc == INVALID_SOCKET) { return -1; } // error, socket init fail
	
	l=get_sv_name(request_URL,svName);
	strcpy(reqPage,request_URL+l);
	//printf("server name:%s\n",svName); printf("request page:%s\n",reqPage);
	
	// port number
	port=80;
	
	// server ip address
	sv_addr = inet_addr((char*)svName); // check svName is in format "xx.xx.xx.xx"
	if (sv_addr == -1) {
		host1 = gethostbyname(svName); // get host info from svName
		if (host1 != NULL) { sv_addr = *((unsigned long *)((host1->h_addr_list)[0])); }
	}
	if (sv_addr == -1) {
		closesocket(soc); return -1; // error, cannot get host address
	}
	
	// open server
	server1.sin_family = AF_INET;
	server1.sin_addr.s_addr = sv_addr;
	server1.sin_port = htons((unsigned short)port);
	memset(server1.sin_zero,(int)0,sizeof(server1.sin_zero));
	if (connect(soc,(struct sockaddr *)&server1,sizeof(server1))==SOCKET_ERROR) {
		closesocket(soc); return -1; // error, cannot connect
	}
	
	// send 'GET'-request
	sprintf(sendbuf,"GET %s HTTP/1.0\r\nHost: %s:%d\r\nUser-Agent: aaa/0.0\r\n\r\n",reqPage,svName,port);	/* リクエストヘッダを作成する */
	if (send(soc,sendbuf,strlen(sendbuf),0) == SOCKET_ERROR){
		shutdown(soc,2); closesocket(soc); return -1; // error, cannot send req
	}
	
	// receive result (save to file)
	fp=fopen(savefile,"wb");
	if (fp==NULL) {
		shutdown(soc,2); closesocket(soc); return -1; // error, cannot create savefile
	}
	sep=0;
	while (1) {
		buf_len = recv(soc,recvbuf,1023,0);
		if (buf_len==0) { break; } // exit
		if (buf_len==SOCKET_ERROR) { break; } // error, cannot receive
		recvbuf[buf_len]='\0';
		l=0;
		if (sep==0) {
			for (i=0;i<buf_len;i++) {
				//printf("%c",recvbuf[i]);
				if ( (recvbuf[i]==0x0A)&&(recvbuf[i+1]==0x0A) ) { l=i+2; break; }
				if ( (recvbuf[i]==0x0D)&&(recvbuf[i+1]==0x0D) ) { l=i+2; break; }
				if ( (recvbuf[i]==0x0D)&&(recvbuf[i+1]==0x0A)&&(recvbuf[i+2]==0x0D)&&(recvbuf[i+3]==0x0A) ) { l=i+4; break; }
			}
			if (l>0) { sep=1; }
		}
		for (i=l;i<buf_len;i++) { fputc(recvbuf[i],fp); }
	}
	fclose(fp);
	shutdown(soc,2);
	closesocket(soc);
	WSACleanup();
	return 0;
}

int Can_I_reach_Server(char *server_name)
{
	int soc,ret,res;
	WORD version;
	WSADATA wsaData;
	struct hostent *host;

	version = MAKEWORD(1,1);
	ret = WSAStartup(version, &wsaData);
	if (ret != 0) { return -1; } // winsock init error
	soc = socket(PF_INET,SOCK_STREAM,0);
	if (soc == INVALID_SOCKET) { return -1; } // socket init errror
	
	res=0;
	host = gethostbyname(server_name);
	if (host != NULL) { res = 1; } // found
	
	closesocket(soc); 
	WSACleanup();
	return res;
}

int Get_GoogleMaps_Pict(double lat,double lng,int maptype)
{
	char URLdata[1024];

	if ( Can_I_reach_Server("google.com") != 1 ) {
		//printf("Google.comに接続できません\n"); getchar(); exit(1);
		return -1;
	}
	
	// get picture
	strcpy(URLdata,"http://maps.googleapis.com"); // server name
	strcat(URLdata,"/maps/api/staticmap"); // static map api
	sprintf(URLdata,"%s?center=%.6f,%.6f",URLdata,lat,lng); // Latitude & Longitude
	strcat(URLdata,"&hl=en"); // English
	strcat(URLdata,"&zoom=15"); // Zoom
	strcat(URLdata,"&size=600x600"); // picture size
	strcat(URLdata,"&format=png"); // picture format
	if (maptype==1) { strcat(URLdata,"&maptype=roadmap"); }  // map type1
	if (maptype==2) { strcat(URLdata,"&maptype=terrain"); }  // map type2
	if (maptype==3) { strcat(URLdata,"&maptype=satellite"); }// map type3
	if (maptype==4) { strcat(URLdata,"&maptype=hybrid"); }   // map type4
	sprintf(URLdata,"%s&markers=%.6f,%.6f,tiny",URLdata,lat,lng); // marker
	strcat(URLdata,"&key=");
	strcat(URLdata,GOOGLE_MAPS_API_KEY);
	
	Wget_file("map_pict.png",URLdata);
	
	return 0;
}

int main()
{
	double lat,lng;
	lat = 35.1704;   lng = 136.882; // 名古屋駅の緯度,経度
	if (Get_GoogleMaps_Pict(lat,lng,1)== -1) { // Googleから地図画像をとってくる
		printf("Error\n"); getchar(); return -1;
	} else {
		printf("Ok. PNG file generated.\n"); getchar();
	}
	return 0;
}

google_maps_api_key.hについては、先日のGeolocation APIの話に書いたように各自で用意する。

そして、次のようなMakefileを使ってnmakeでビルドする。

OBJS	=	main.obj get_googlemaps_pict.obj

CFLAGS	=	/c /MT

.cpp.obj:
	cl $(CFLAGS) $<

main.exe:	$(OBJS)
	cl $(OBJS) wsock32.lib user32.lib

Visual Studio 2017でビルドした。

できあがったexeファイルを実行すると、
map_pict.pngという画像ファイルが生成される。


ゼンリンの地図が得られていたのだが、最近Googleはゼンリンの地図を使うのをやめてGoogle製の地図に変更してしまっている。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Time limit is exhausted. Please reload CAPTCHA.

− 5 = 3