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