JPGのExif情報に直接読み書きしてマップに表示。
PHPを使い、JPGのExif情報に直接読み書きしてマップに表示してみました。
こんな感じ。
http://www.moeten.info/flex/20081205_exifPHP/bin-release/main.html
前回との違いは直接JPGファイルに埋め込まれているExifをいじってます。
アイコンをドラッグするとJPGファイルのExifの緯度経度情報を更新します。
これだとデータベースが入らないのが便利ですね。
あとExifは撮影日や細かいカメラ設定も取得することができるので、旅記録としてはかなり便利。
メイン部分の簡単な説明
マーカードラッグ完了イベントでサーバーへ情報を送信
marker.addEventListener(MapMouseEvent.DRAG_END , function():void{ htsFileUpdate.send({ "fname" :myFname, "lat":marker.getLatLng().lat(), "lon":marker.getLatLng().lng() }); });
if( $_GET['mode'] == "update" && $_GET['fname'] != "" && $_GET['lat'] != "" && $_GET['lon'] != "" ){ //Exif情報の更新 $safe_a = array( ".." , "/" ); $safe_b = array( "" , "" ); $fname = "image/" . str_replace( $safe_a , $safe_b , $_GET['fname'] ); if( ! file_exists( $fname ) )exit; $lat = substr( $_GET['lat'] , 0 , 20 ); $lon = substr( $_GET['lon'] , 0 , 20 ); $gps = degree2dms( $lat , $lon ); $lat_a = explode( "." , $gps["lat"] ); $lon_a = explode( "." , $gps["lon"] ); //GPS情報の書き込み $jpeg = new PelJpeg( $fname ); $ifd0 = $jpeg->getExif()->getTiff()->getIfd(); $ifd0->getSubIfd(PelIfd::GPS); $gps = new PelIfd(PelIfd::GPS); $ifd0->addSubIfd($gps); $gps->addEntry(new PelEntryRational(PelTag::GPS_LATITUDE, array($lat_a[0], 1), array($lat_a[1], 1), array($lat_a[2], 100))); $gps->addEntry(new PelEntryAscii( PelTag::GPS_LATITUDE_REF, 'N')); $gps->addEntry(new PelEntryRational(PelTag::GPS_LONGITUDE, array($lon_a[0], 1), array($lon_a[1], 1), array($lon_a[2], 100))); $gps->addEntry(new PelEntryAscii( PelTag::GPS_LONGITUDE_REF, 'E')); file_put_contents( $fname , $jpeg->getBytes() ); }
参考リンク
すべてのソースコードはこちら
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(); } 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 + "-" + myXMLDATA[i].fname; 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 myFname:String = String( LoaderInfo(e.currentTarget).loader.name ).split("-")[2]; 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; marker.addEventListener(MapMouseEvent.DRAG_END , function():void{ myXMLDATA[myI].lat = marker.getLatLng().lat(); myXMLDATA[myI].lng = marker.getLatLng().lng(); htsFileUpdate.send({ "fname" :myFname, "lat":marker.getLatLng().lat(), "lon":marker.getLatLng().lng() }); }); 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/20081205_exifPHP/" resultFormat="e4x" result="onHtsFileListResultHandler(event)"/> <mx:HTTPService id="htsFileUpdate" url="http://www.moeten.info/flex/20081205_exifPHP/?mode=update" resultFormat="e4x"/> <!--############ ############--> <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(Direct)" color="0x999999" fontSize="30"/> <mx:HRule x="10" y="52" width="825" height="8"/> </mx:Application>
<?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) { $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; } } return $exif; } //角度を度分秒表記に変換 function degree2dms( $lat , $lon ){ $lat_lon = array( "lat" => $lat, "lon" => $lon, ); foreach( $lat_lon as $key => $degree ){ $d = floor($degree); $m = floor(($degree-$d)*60); $s = floor(($degree-$d-$m/60)*3600); $u = floor(($degree-$d-$m/60-$s/3600)*360000); $s = $s * 100 + $u ; $dms = "$d.$m.$s"; $gps[$key] = $dms; } return( $gps ); } //度分秒表記を角度に変換 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['lon'] = $posE; return $gps; } require_once('pel/PelJpeg.php'); if( $_GET['mode'] == "" ){ //Exif情報を配列へ $xml = <<<EOD <result> EOD; $dir = dir( "./image" ); while( $item = $dir->read() ){ if( $item != ".." && $item != "." ){ $fname = "image/{$item}"; 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); $xml .= <<<EOD <item> <id>{$cnt}</id> <image>http://www.moeten.info/flex/20081205_exifPHP/image/{$item}</image> <fname>{$item}</fname> <lat>{$gps['lat']}</lat> <lng>{$gps['lon']}</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; }elseif( $_GET['mode'] == "update" && $_GET['fname'] != "" && $_GET['lat'] != "" && $_GET['lon'] != "" ){ //Exif情報の更新 $safe_a = array( ".." , "/" ); $safe_b = array( "" , "" ); $fname = "image/" . str_replace( $safe_a , $safe_b , $_GET['fname'] ); if( ! file_exists( $fname ) )exit; $lat = substr( $_GET['lat'] , 0 , 20 ); $lon = substr( $_GET['lon'] , 0 , 20 ); $gps = degree2dms( $lat , $lon ); $lat_a = explode( "." , $gps["lat"] ); $lon_a = explode( "." , $gps["lon"] ); //GPS情報の書き込み $jpeg = new PelJpeg( $fname ); $ifd0 = $jpeg->getExif()->getTiff()->getIfd(); $ifd0->getSubIfd(PelIfd::GPS); $gps = new PelIfd(PelIfd::GPS); $ifd0->addSubIfd($gps); $gps->addEntry(new PelEntryRational(PelTag::GPS_LATITUDE, array($lat_a[0], 1), array($lat_a[1], 1), array($lat_a[2], 100))); $gps->addEntry(new PelEntryAscii( PelTag::GPS_LATITUDE_REF, 'N')); $gps->addEntry(new PelEntryRational(PelTag::GPS_LONGITUDE, array($lon_a[0], 1), array($lon_a[1], 1), array($lon_a[2], 100))); $gps->addEntry(new PelEntryAscii( PelTag::GPS_LONGITUDE_REF, 'E')); file_put_contents( $fname , $jpeg->getBytes() ); } ?>