PHPで画像のEXIF(位置情報)を取得する方法

PHPで画像のEXIF(位置情報)を取得する方法

撮影した写真などのExifにはGPSデータが含まれていることは、知っている人も多いんじゃないかと思います。スマホ全盛期の今では、web制作者にとって位置情報の活用は欠かせない技術と言えますね。今回はPHPを利用して、画像ファイルから位置情報を取得する方法を紹介します。

サンプルデモ

画像から位置情報を取得する
画像から位置情報を取得する

画像ファイルを指定すると、その画像に含まれる位置情報を取得し、Google Mapsなどに対応した10進数の緯度、経度に変換します。

サンプルデモを見る

[exif_read_data()]を利用する

画像ファイルのExifデータを取得するには、exif_read_data()という関数を利用します。公式マニュアルによる解説は、下記ページをご覧下さい。

exif_read_data()の使い方は極めて簡単で、引数に画像ファイルのパスを指定するだけです。http://〜形式は不可です。つまり外部サーバーのファイルを指定できない点にご注意下さい。画像ファイルにExifが含まれていた場合はデータを配列形式で取得できます。含まれていない場合はfalseが返ります。

下記サンプルコードです。お手持ちの写真のExifを取得してみて下さい。

PHP

<?php

	// 画像ファイルのパス (相対パス)
	$img = './photo.jpg' ;

	// Exifを取得し、[$exif]に代入する
	$exif = @exif_read_data( $img ) ;

	// 取得したデータを確認する
	echo '<pre>' ;
	var_dump( $exif ) ;
	echo '</pre>' ;

位置情報の取得方法

Exifのサンプル

例えば、下記写真から取得できるExifデータを紹介します。

サンプルの写真

この写真を関数で読み取ると、下記の構造のデータを配列形式で取得することができます。

JSON

{
    "FileName": "photo.jpg",
    "FileDateTime": 0,
    "FileSize": 125729,
    "FileType": 2,
    "MimeType": "image/jpeg",
    "SectionsFound": "ANY_TAG, IFD0, COMMENT, EXIF, GPS",
    "COMPUTED": {
        "html": "width=\"800\" height=\"600\"",
        "Height": 600,
        "Width": 800,
        "IsColor": 1,
        "ByteOrderMotorola": 1,
        "ApertureFNumber": "f/2.4"
    },
    "Make": "Apple",
    "Model": "iPhone 5",
    "Orientation": 1,
    "XResolution": "72/1",
    "YResolution": "72/1",
    "ResolutionUnit": 2,
    "Software": "iPhoto 9.5.1",
    "DateTime": "2014:07:03 11:56:33",
    "Exif_IFD_Pointer": 200,
    "GPS_IFD_Pointer": 942,
    "COMMENT": [
        "Optimized by JPEGmini 3.11.4.3 0xafdc7f37"
    ],
    "ExposureTime": "1/1085",
    "FNumber": "12/5",
    "ExposureProgram": 2,
    "ISOSpeedRatings": 50,
    "ExifVersion": "0221",
    "DateTimeOriginal": "2014:07:03 11:56:33",
    "DateTimeDigitized": "2014:07:03 11:56:33",
    "ComponentsConfiguration": "\u0001\u0002\u0003\u0000",
    "ShutterSpeedValue": "10819/1073",
    "ApertureValue": "4845/1918",
    "BrightnessValue": "13896/1579",
    "MeteringMode": 3,
    "Flash": 16,
    "FocalLength": "103/25",
    "SubjectLocation": [
        1454,
        1161,
        541,
        541
    ],
    "SubSecTimeOriginal": "037",
    "SubSecTimeDigitized": "037",
    "FlashPixVersion": "0100",
    "ColorSpace": 1,
    "ExifImageWidth": 800,
    "ExifImageLength": 600,
    "SensingMethod": 2,
    "SceneType": "\u0001",
    "ExposureMode": 0,
    "WhiteBalance": 0,
    "FocalLengthIn35mmFilm": 33,
    "SceneCaptureType": 0,
    "UndefinedTag:0xA432": [
        "103/25",
        "103/25",
        "12/5",
        "12/5"
    ],
    "UndefinedTag:0xA433": "Apple",
    "UndefinedTag:0xA434": "iPhone 5 back camera 4.12mm f/2.4",
    "GPSLatitudeRef": "N",
    "GPSLatitude": [
        "35/1",
        "48/1",
        "986/100"
    ],
    "GPSLongitudeRef": "E",
    "GPSLongitude": [
        "139/1",
        "47/1",
        "1953/100"
    ],
    "GPSAltitudeRef": "\u0000",
    "GPSAltitude": "467/128",
    "GPSTimeStamp": [
        "2/1",
        "56/1",
        "32/1"
    ],
    "GPSImgDirectionRef": "M",
    "GPSImgDirection": "3891/1894",
    "GPSDateStamp": "2014:07:03"
}

必要なプロパティ

Exifには、実に膨大な量の情報が含まれているのが分かったと思います。ですが、今回の目的である「位置情報」を取得するために必要なのは、その内、GPSLatitudeRefGPSLatitudeGPSLongitudeRefGPSLongitudeの4つのプロパティのみです。

JSON

{
    "GPSLatitudeRef": "N",
    "GPSLatitude": [
        "35/1",
        "48/1",
        "986/100"
    ],
    "GPSLongitudeRef": "E",
    "GPSLongitude": [
        "139/1",
        "47/1",
        "1953/100"
    ]
}

各プロパティの説明は、次の通りです。

キー名説明
GPSLatitudeRef縦軸の方角。Nなら北、Sなら南。
GPSLatitude60進数の緯度。第1〜3要素まで、順に「度」「分」「秒」を表す。
GPSLongitudeRef横軸の方角。Eなら東、Wなら西。
GPSLongitude60進数の経度。第1〜3要素まで、順に「度」「分」「秒」を表す。

60進数から10進数に変換する

緯度と経度、それぞれの方角と、60進数の数値(度、分、秒)を取得することができました。しかし、Google Mapsなどに見られるように、一般的に利用するのは、33.6231,135.9324というような10進数の値だと思います。60進数を10進数に変換する計算方法は次の通りです。方角が南(南緯)、西(西経)の場合、値はマイナスとなります。

[度] + [分 ÷ 60] + [秒 ÷ 3600]

この公式を踏まえて、PHPで変換する処理を書くと、次の通りになります。986/100というように文字列状態の値をまずは計算に利用できる数値に直す必要がありますね。緯度と経度、それぞれに適用する処理は同じなので、関数化しておいた方が便利でしょう。

get-exif-10from60.php

<?php
/********************************************************

	Exifデータの位置情報を60進数から10進数に変換する関数
		第1引数:進行方向(["GPSLatitudeRef"]、["GPSLongitudeRef"])
		第2引数:60進数の配列(["GPSLatitude"]、["GPSLongitude"])
		返り値:10進数に直したデータ

	解説: https://syncer.jp/php-exif-read-data

********************************************************/

function get_10_from_60_exif( $ref , $gps )
{
	// 60進数から10進数に変換
	$data = convert_float( $gps[0] ) + ( convert_float($gps[1])/60 ) + ( convert_float($gps[2])/3600 ) ;

	//南緯、または西経の場合はマイナスにして返却
	return ( $ref=='S' || $ref=='W' ) ? ( $data * -1 ) : $data ;
}

// [例:986/100]という文字列を[986÷100=9.86]というように数値に変換する関数
function convert_float( $str )
{
	$val = explode( '/' , $str ) ;
	return ( isset($val[1]) ) ? $val[0] / $val[1] : $str ;
}

ダウンロード

写真から位置情報を取得するサンプルプログラムを配布します。ぜひ、あなたのウェブサービスに活かして下さい。

ファイル一覧

SYNCER00174
get-latlng-from-exif.php Download
get-exif-10from60.php Download
photo-01.jpg Download
photo-02.jpg Download
photo-03.jpg Download
photo-04.jpg Download

ファイル名をクリックすると内容を確認できます。「Download Zip」をクリックするとファイル一式をダウンロードできます。

Download Zip