JPG画像のExifから緯度経度情報を読んでマップに張り付ける。

JPG画像のExifから緯度経度情報を読んでマップに張り付けてみました。
こんな感じ
http://www.moeten.info/flex/20081204_jpg2mapbyexif/bin-release/main.html

Exifっていろいろな情報があってとっても便利です。

PHPを使用して、Exif情報を取り出すだけなので結構簡単にできます。

PHPでJPG画像からExif情報を読む方法。

//Exif情報を配列へ
$cls = exif_read_data($fname, 'EXIF');
foreach ($cls as $key=>$sect) {
    if (is_array($sect) == FALSE) {
        $exif[$key] = $sect;
    } else {
        foreach($sect as $name=>$val)$exif[$key . '.' . $name] = $val;
    }
}

読み込んだ情報をFlexが扱いやすいxml形式にて表示します。
http://www.moeten.info/flex/20081204_jpg2mapbyexif/index.php
PHPAIRExif情報の書き込みができればもっと便利だろうなぁ。
すべてのソースコードはこちら
Flexソースコードはこちら

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    creationComplete="creationCompleteHandler(event)" backgroundGradientColors="[0xffffff,0x999999]" viewSourceURL="srcview/index.html">
<mx:Script>
<![CDATA[
import com.google.maps.MapEvent;
import com.google.maps.LatLng;
import com.google.maps.Map;
import com.google.maps.InfoWindowOptions;
import com.google.maps.styles.*;
import com.google.maps.interfaces.IPolyline;
import com.google.maps.overlays.*;
import com.google.maps.controls.*;
import com.google.maps.*;
import com.google.maps.services.*;
[Bindable]public var myXMLDATA:XMLList;
//マップ作製
private var map:Map;
private function creationCompleteHandler(e:Event):void{
    makeMap();
}
private function makeMap():void{
    map = new Map();
    map.key = "ABQIAAAAq9Z1Z3_S-AQpWPqQe5Gh1RRD4wMK23XJSE0pd0Xt9l-AeMpaYxRIezvnX8EKJ4gZ1xqmuo8WFOd9LA";
    myUI.addChild( map );
    map.language = "JP";
    map.width = myUI.width;
    map.height = myUI.height;
    map.addEventListener( MapEvent.MAP_READY, onMapReady );
}
private function onMapReady(e:Event):void{
    //装飾追加
    var zoomControl:ZoomControl = new ZoomControl()
    var z:ZoomControlOptions    = new ZoomControlOptions();
    map.addControl(zoomControl);
    var pos:PositionControl     = new PositionControl();
    map.addControl(pos);
    map.enableContinuousZoom();
    map.setCenter( new LatLng(34.50655662164561,134.835205078125)  , 7, MapType.NORMAL_MAP_TYPE );
    htsFileList.send();
}
/*
//画像ファイルを選択
import flash.net.FileReference;
private var myFileReferenceList:FileReferenceList;
private function fileSelect():void{
    myFileReferenceList = new FileReferenceList();
    myFileReferenceList.browse( new Array( new FileFilter("Images (*.jpg,*.jpeg)", "*.jpg;*.jpeg") ) );
    myFileReferenceList.addEventListener(Event.SELECT , selectHandler );
}
private var urlRequest:URLRequest;
private function selectHandler(e:Event):void{
    var urlVariables:URLVariables = new URLVariables();
    urlVariables.imgMaxWidth  = 100;
    urlVariables.imgMaxHeight = 200;
    urlRequest = new URLRequest();
    urlRequest.url = "http://moeten.info/flex/20081204_jpg2mapbyexif/?mode=fileupload";
    urlRequest.method = URLRequestMethod.POST;
    urlRequest.data = urlVariables;
    for (var i:int = 0; i < myFileReferenceList.fileList.length ; i++ ){
        var fileReference:FileReference = new FileReference();
        fileReference = FileReference( myFileReferenceList.fileList[i] );
        fileReference.addEventListener( DataEvent.UPLOAD_COMPLETE_DATA, onUploadCompleteData );
        fileReference.upload( urlRequest );
   }
}
private function onUploadCompleteData(e:Event):void{
}
*/
private var markerArr:Array = new Array();
private function onHtsFileListResultHandler(e:Event):void{
    myXMLDATA = htsFileList.lastResult.item;
    for( var i:int = 0 ; i < myXMLDATA.length() ; i ++ ){
        if( myXMLDATA[i].lat != "" && myXMLDATA[i].lng != "" ){
            if(markerArr[myXMLDATA[i].id])return;
            var loader:Loader = new Loader();
            loader.name = "" + i + "-" + myXMLDATA[i].id;
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE , function(e:Event):void{
                var myBitmap:Bitmap = Bitmap(LoaderInfo(e.currentTarget).content);
                myBitmap.width   = 40;
                myBitmap.height  = 40;
                myBitmap.filters = [gf];
                var myI:int = int( String( LoaderInfo(e.currentTarget).loader.name ).split("-")[0]);
                var myId:int = int( String( LoaderInfo(e.currentTarget).loader.name ).split("-")[1]);
                var marker:Marker = new Marker(
                                                new LatLng( myXMLDATA[myI].lat , myXMLDATA[myI].lng ) ,
                                                new MarkerOptions({
                                                    draggable :true,
                                                    icon:myBitmap,
                                                    iconAlignment: MarkerOptions.ALIGN_HORIZONTAL_CENTER,
                                                    hasShadow:true
                                                })
                                            );
                markerArr[myId] = marker;
                map.addOverlay(marker);
            });
            loader.load( new URLRequest( myXMLDATA[i].image ) );
        }
    }
}
private function onItemSelected(e:Event):void{
    map.panTo( new LatLng( dg.selectedItem.lat , dg.selectedItem.lng ) );
}
]]>
</mx:Script>
<!--############  ############-->
<mx:GlowFilter id="gf" color="0xffffff" blurX="4" blurY="4" strength="10"/>
<!--############  ############-->
<mx:HTTPService id="htsFileList" url="http://www.moeten.info/flex/20081204_jpg2mapbyexif/index.php" resultFormat="e4x"
    result="onHtsFileListResultHandler(event)"/>
<!--############  ############-->
<mx:UIComponent id="myUI" width="507" height="533" x="10" y="66"/>
<mx:DataGrid id="dg" x="525" y="66" width="310" height="533" dataProvider="{htsFileList.lastResult.item}"
    backgroundAlpha="0.5" itemClick="onItemSelected(event)">
    <mx:columns>
        <mx:DataGridColumn headerText="画像">
            <mx:itemRenderer>
                <mx:Component>
                    <mx:Image width="50" height="50" source="{data.image}"/>
                </mx:Component>
            </mx:itemRenderer>
        </mx:DataGridColumn>
        <mx:DataGridColumn headerText="撮影日" dataField="date"/>
        <mx:DataGridColumn headerText="緯度" dataField="lat"/>
        <mx:DataGridColumn headerText="経度" dataField="lng"/>
    </mx:columns>
</mx:DataGrid>
<mx:Label x="10" y="10" text="Exif2Map" color="0x999999" fontSize="30"/>
    <mx:HRule x="10" y="52" width="825" height="8"/>
</mx:Application>

PHPソースコードはこちら

<?php
$CodeInternal = 'SJIS';//内部処理コード
$CodeExport   = 'SJIS';//出力コード
mb_internal_encoding($CodeInternal);
mb_regex_encoding($CodeInternal);
function d() {
    echo '<pre style="background:#fff;color:#333;border:1px solid #ccc;margin:2px;padding:4px;font-family:monospace;font-size:12px">';
    foreach (func_get_args() as $v) var_dump($v);
    echo '</pre>';
}
function getexif($fname, &$exif) {
    //ファイルの存在チェック
    if (file_exists($fname) == FALSE)    return (-1);
    //JPEG/TIFFの型チェック
    switch (exif_imagetype($fname)) {
        case IMAGETYPE_JPEG:
        case IMAGETYPE_TIFF_II:
        case IMAGETYPE_TIFF_MM:
            break;
        default:
            return (-2);
    }
    //Exif情報を配列へ
    if (($cls = exif_read_data($fname, 'EXIF')) == FALSE)    return (-3);
    foreach ($cls as $key=>$sect) {
        if (is_array($sect) == FALSE) {
            $exif[$key] = $sect;
        } else {
            foreach($sect as $name=>$val)    $exif[$key . '.' . $name] = $val;
        }
    }
    return 0;
}
//度分秒表記を角度に変換
function dms2degree( $pos_n , $pos_e ){
    $posN_a = explode( "." , $pos_n );
    $posE_a = explode( "." , $pos_e );
    //$posN_a[2] = $posN_a[2] . "." .$posN_a[3];
    //$posE_a[2] = $posE_a[2] . "." .$posE_a[3];
    $posN = $posN_a[0] + $posN_a[1]/60 + $posN_a[2]/3600;//北緯
    $posE = $posE_a[0] + $posE_a[1]/60 + $posE_a[2]/3600;//東経
    $gps['lat'] = $posN;
    $gps['lng'] = $posE;
    return $gps;
}
//Exif情報を配列へ
$xml = <<<EOD
<result>
EOD;
$cnt = 0;
$dir = dir( "image" );
while( $list = $dir->read() ){
    if( $list != "." && $list != ".." ){
        $fname = "image/{$list}";
        if (($cls = exif_read_data($fname, 'EXIF')) == FALSE)    return (-3);
        foreach ($cls as $key=>$sect) {
            if (is_array($sect) == FALSE) {
                $exif[$key] = $sect;
            } else {
                foreach($sect as $name=>$val){
                    $exif[$key . '.' . $name] = $val;
                }
            }
        }
        $date = $exif["DateTimeOriginal"];
        $lat_a0 = explode( "/" , $exif['GPSLatitude.0'] );
        $lat_a1 = explode( "/" , $exif['GPSLatitude.1'] );
        $lat_a2 = explode( "/" , $exif['GPSLatitude.2'] );
        $lat_a2[0] = $lat_a2[0]/100;
        $pos_n = "{$lat_a0[0]}.{$lat_a1[0]}.{$lat_a2[0]}";
        $lng_a0 = explode( "/" , $exif['GPSLongitude.0'] );
        $lng_a1 = explode( "/" , $exif['GPSLongitude.1'] );
        $lng_a2 = explode( "/" , $exif['GPSLongitude.2'] );
        $lng_a2[0] = $lng_a2[0]/100;
        $pos_e = "{$lng_a0[0]}.{$lng_a1[0]}.{$lng_a2[0]}";
        $gps = dms2degree($pos_n,$pos_e);
        //d( $exif );
        $xml .= <<<EOD
  <item>
    <id>{$cnt}</id>
    <image>http://www.moeten.info/flex/20081204_jpg2mapbyexif/image/{$list}</image>
    <lat>{$gps['lat']}</lat>
    <lng>{$gps['lng']}</lng>
    <date>{$date}</date>
    <timestamp>{$exif['FileDateTime']}</timestamp>
  </item>
EOD;
        $cnt ++;
    }
 }
$xml .= <<<EOD
</result>
EOD;
header ("Content-Type: text/xml; charset=UTF-8");
echo $xml;
exit;
?>