2009年08月01日 16:00 [Edit]

Ajax - URIのJPEGからEXIFを抜いて、Google Mapsで表示する

それでは、ピンポイントでお答えしましょう。

ディスカヴァー社長室blogディスカヴァー社長室blog: ここはどこ?〜干場
ディズニーシーより混んでいる。

(追記:IEでの不具合を修正)


ずばり、ここです。

Demo


なつかしいなあ。妻と入籍する前の婚前旅行で行きましたよ。Caffe Florianにはたちよりました?しっかり勘定に"Musica"って入ってました?

ということを簡単に実現するための仕組みです。

やってることは単純で、JPEGからEXIFをぶっこぬいて、そこにある緯度経度に Google Map をセンタリングしているだけ。強いて面倒な点をあげると、EXIFの緯度経度は度分秒で表現されているのに対し、Google Map は度のみなこと。これはdms2deg()で変換しています。

JS Source:

<script type="text/javascript" src="http://www.google.com/jsapi?key=yourkey"></script>
(function(d){

var gmap = {};

google.load('maps', '2');

google.setOnLoadCallback(function(){
    gmap.map = new google.maps.Map2(d.getElementById('gmap'));
    gmap.map.addControl(new GSmallMapControl());
    gmap.map.addControl(new GMapTypeControl());
    gmap.geocoder = new google.maps.ClientGeocoder();
});

window.onunload=function(ev){  GUnload() }

var dms2deg = function(src){
  var deg = 0; /* 45 deg 26' 1.80" N */
  src.replace(/(\d+)\D*(\d+)\D*(\d+\.\d+)\D*([NSEW])/, function(a,d,m,s,nsew){
    deg = parseInt(d,10) + parseInt(m,10)/60 + parseFloat(s)/3600;
    deg *= nsew === 'N' ? 1 : nsew === 'E' ? 1 : -1;
  });
  return deg;
}; 

JSONP = {
  get:function(uri, cb){
    if (!cb) cb = 'JSONP.run';
    d.getElementById('exifsrc').src = uri;
    var u = ['http://api.dan.co.jp/exif', cb, uri].join('/');
    var s = d.createElement('script');
    s.charset = 'UTF-8';
    s.id = s.src = u;
    d.body.appendChild(s);
  },
  run:function(json){
    var point = new GLatLng(
        dms2deg(json.GPSLatitude), 
        dms2deg(json.GPSLongitude)
    );
    gmap.map.setCenter(point, 12);
    var marker = new google.maps.Marker(point);
    gmap.map.addOverlay(marker);
    var html = [
      '緯度:' + point.y,
      '経度:' + point.x,
      '日時:' + json.DateTimeOriginal
    ].join('<'+'br>');
    google.maps.Event.addListener(marker, "click", function() {
        marker.openInfoWindowHtml(html);
    });
  }
}

})(document);

Server Source:

EXIFをぶっこぬいてJSONPで返すだけの単純なScriptです。例によってCGIでもmod_perlでも動きます。

exif.cgi
#!/usr/local/bin/perl
#
# $Id: exif.cgi,v 0.1 2009/08/01 06:00:53 dankogai Exp dankogai $
#
use strict;
use warnings;
use LWP::UserAgent;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;
use Image::ExifTool;
use JSON::Syck;

my $q = CGI->new;
my ( $callback, $uri ) = ( $q->path_info =~ m,^/([^/]+)/(.*),o );
$callback or die 'no callback!';
$uri =~ s,^(https?:)/+,$1//,o
  or die 'invalid scheme: ', $q->escapeHTML($uri);
$uri .= '?' . $ENV{QUERY_STRING} if $ENV{QUERY_STRING};

my $res = LWP::UserAgent->new->get($uri);
die "$uri ", $res->status_line unless $res->is_success;
die "$uri ", $res->headers->header('content-type'), " is not supported"
  unless $res->headers->header('content-type') =~ m{\Aimage/jpeg};
my $image = $res->content;

my $tool = Image::ExifTool->new;
my $exif = $tool->ImageInfo( \$image );
$exif->{uri} = $uri;

print
  "Content-Type: application/x-javascript; charset=utf-8\n\n",
  "$callback(", JSON::Syck::Dump( $exif ), ");\n";

Enjoy!

Dan the AJAXen


この記事へのトラックバックURL

この記事へのコメント
あれ?グーグルマップみれませんよ。firefoxです。
Posted by クルックル at 2009年08月01日 17:25
FireFox:NG
IE:NG
Safari:OK

でした。
Posted by sumi at 2009年08月01日 17:32
Firefox 3.0ですが見えてますね
上の方々は3.5?
Posted by Yugo at 2009年08月01日 17:57
各位、
IEでも動くよう修正しました。
IEでは、global objectと同じ名前のDOM ObjectがあるとObject Errorがでちゃうんですよね><。そこが問題でした。
Dan the IEphobia
Posted by at 2009年08月01日 17:58
直りましたね。

FireFox(3.5)もIE(8)もOKです。
Posted by sumi at 2009年08月01日 18:01
Opera 9.64ではNGです
Posted by konzertnr9 at 2009年08月01日 23:47
上撤回です。なにやってんだか……。
Posted by konzertnr9 at 2009年08月01日 23:48
おいらfirefox3.5(mac)ですがみれません><
Posted by とんぼ at 2009年08月02日 13:11
> deg = parseInt(d) + parseInt(m)/60 + parseFloat(s)/3600;
deg = parseInt(d,10) + parseInt(m,10)/60 + parseFloat(s)/3600;
では?

Posted by masa at 2009年08月03日 13:31