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製の地図に変更してしまっている。