PHP-PhotoGps
is a simple library to get GPS data from a photo.
This library reads EXIF data of a jpeg file,
and can convert latitude/longitude into sexagesimal(English/Japanese) or decimal formats,
converts directions into degree with arrow images ,
converts speeds, date stamps and time stamps into human-readable strings.
Remote files (via http: or https:) are supported.
Supported Exif Versions:
- 3.0
- 2.32
- 2.31
- 2.3
- 2.21
- 2.2
- 2.1
- 1. Features
- 2. Contents
- 3. Requirements
- 4. Installation
- 5. Usage
- 6. Examples
- 7. LICENSE
- 8. Changelog
-
PHP 8.1 or later
-
GD library enabled
check with commands:
(php -m; php -i) | grep gd
-
Exif enabled
check with commands:
(php -m; php -i) | grep exif
composer require macocci7/php-photo-gps
- 5.1. Usage: Basic
- 5.2. Usage: Format Configuration
- 5.3. Usage: Photo List with Checking Geo Data
- 5.4. Usage: Read All GPS Tags
- 5.5. Usage: GPS Attribute Information
-
<?php require_once __DIR__ . '/../vendor/autoload.php'; use Macocci7\PhpPhotoGps\PhotoGps; $filename = 'img/with_gps.jpg'; // includes GPS tags $pg = new PhotoGps($filename); echo "[" . $filename . "]--------------------\n"; // Latitude in sexagesimal format echo "Latitude: " . $pg->latitudeS() . "\n"; echo "緯度: " . $pg->lang('ja')->latitudeS() . "\n"; // Longitude in sexagesimal format echo "Longitude: " . $pg->lang('eng')->longitudeS() . "\n"; echo "経度: " . $pg->lang('ja')->longitudeS() . "\n"; // Altitude as strings echo "Altitude: " . $pg->lang('eng')->altitudeS() . "\n"; echo "高度: " . $pg->lang('ja')->altitudeS() . "\n"; // Coord in decimal format ('S' and 'W' results in negative value.) echo "Coord: " . $pg->latitudeD() . ", " . $pg->longitudeD() . "\n";
-
[img/with_gps.jpg]-------------------- Latitude: 37°3'26.2"N 緯度: 北緯37度3分26.2秒 Longitude: 140°53'32.8"E 経度: 東経140度53分32.8秒 Altitude: (Above Ellipsoidal Surface) 13.00 m 高度: (正値楕円体高) 13.00 メートル Coord: 37.057274166667, 140.89244166667
-
Import autoloader:
require_once __DIR__ . '/../vendor/autoload.php'
-
use
declaration:use Macocci7\PhpPhotoGps\PhotoGps;
-
Instantiation:
new PhotoGps()
ornew PhotoGps($path)
- Note: If HTTP or HTTPS url is specified as
$path
,download
directory will be created in current directory, and the image will be downloaded in it.
- Note: If HTTP or HTTPS url is specified as
-
Language:
eng
as default.- Get Current:
lang()
- Set as English:
lang('eng')
- Set as Japanese:
lang('ja')
Language Names are defined in
config/PhotoGps.neon
. - Get Current:
-
Latitude:
- Decimal:
latitudeD()
- Sexagesimal:
latitudeS()
- Decimal:
-
Longitude:
- Decimal:
longitudeD()
- Sexagesimal:
longitudeS()
- Decimal:
-
Altitude:
- Decimal:
altitude()
- Strings with prefix & unit:
altitudeS()
- Decimal:
- 5.2.1. Geo Data Format
- 5.2.2. Direction Data Format
- 5.2.3. Speed Data Format
- 5.2.4. Datestamp Data Fromat
- 5.2.5. Timestamp Data Format
for latitudeS()
and longitudeS()
.
-
<?php require_once __DIR__ . '/../vendor/autoload.php'; use Macocci7\PhpPhotoGps\PhotoGps; $filename = 'img/with_gps.jpg'; // includes GPS tags $pg = new PhotoGps($filename); echo "[" . $filename . "]--------------------\n"; // Format: default echo "Current format [eng]: " . $pg->lang('eng')->format() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->format() . "\n\n"; // Latitude in sexagesimal format echo "Latitude: " . $pg->lang('eng')->latitudeS() . "\n"; echo "緯度: " . $pg->lang('ja')->latitudeS() . "\n"; // Longitude in sexagesimal format echo "Longitude: " . $pg->lang('eng')->longitudeS() . "\n"; echo "経度: " . $pg->lang('ja')->longitudeS() . "\n\n"; echo "[Chang format:eng]---------------------------------\n"; // Configure format $pg->lang('eng')->format('{ref:u}: {seconds:v}{seconds:u}, {minutes:v}{minutes:u}, {degrees:v}{degrees:u}'); // Current format echo "Current format [eng]: " . $pg->lang('eng')->format() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->format() . "\n\n"; // Latitude in sexagesimal format echo "Latitude: " . $pg->lang('eng')->latitudeS() . "\n"; echo "緯度: " . $pg->lang('ja')->latitudeS() . "\n"; // Longitude in sexagesimal format echo "Longitude: " . $pg->lang('eng')->longitudeS() . "\n"; echo "経度: " . $pg->lang('ja')->longitudeS() . "\n\n"; echo "[Change format:ja]---------------------------------\n"; // Configure format $pg->lang('ja')->format('{seconds:v}{seconds:u}, {minutes:v}{minutes:u}, {degrees:v}{degrees:u} ({ref:u})'); // Current format echo "Current format [eng]: " . $pg->lang('eng')->format() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->format() . "\n\n"; // Latitude in sexagesimal format echo "Latitude: " . $pg->lang('eng')->latitudeS() . "\n"; echo "緯度: " . $pg->lang('ja')->latitudeS() . "\n"; // Longitude in sexagesimal format echo "Longitude: " . $pg->lang('eng')->longitudeS() . "\n"; echo "経度: " . $pg->lang('ja')->longitudeS() . "\n\n"; echo "[Reset format:ja]---------------------------------\n"; // Reset format $pg->lang('ja')->resetFormat(); // Current format echo "Current format [eng]: " . $pg->lang('eng')->format() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->format() . "\n\n"; // Latitude in sexagesimal format echo "Latitude: " . $pg->lang('eng')->latitudeS() . "\n"; echo "緯度: " . $pg->lang('ja')->latitudeS() . "\n"; // Longitude in sexagesimal format echo "Longitude: " . $pg->lang('eng')->longitudeS() . "\n"; echo "経度: " . $pg->lang('ja')->longitudeS() . "\n\n";
-
[img/with_gps.jpg]-------------------- Current format [eng]: {degrees:v}{degrees:u}{minutes:v}{minutes:u}{seconds:v}{seconds:u}{ref:u} Current format [ja]: {ref:u}{degrees:v}{degrees:u}{minutes:v}{minutes:u}{seconds:v}{seconds:u} Latitude: 37°3'26.2"N 緯度: 北緯37度3分26.2秒 Longitude: 140°53'32.8"E 経度: 東経140度53分32.8秒 [Chang format:eng]--------------------------------- Current format [eng]: {ref:u}: {seconds:v}{seconds:u}, {minutes:v}{minutes:u}, {degrees:v}{degrees:u} Current format [ja]: {ref:u}{degrees:v}{degrees:u}{minutes:v}{minutes:u}{seconds:v}{seconds:u} Latitude: N: 26.2", 3', 37° 緯度: 北緯37度3分26.2秒 Longitude: E: 32.8", 53', 140° 経度: 東経140度53分32.8秒 [Change format:ja]--------------------------------- Current format [eng]: {ref:u}: {seconds:v}{seconds:u}, {minutes:v}{minutes:u}, {degrees:v}{degrees:u} Current format [ja]: {seconds:v}{seconds:u}, {minutes:v}{minutes:u}, {degrees:v}{degrees:u} ({ref:u}) Latitude: N: 26.2", 3', 37° 緯度: 26.2秒, 3分, 37度 (北緯) Longitude: E: 32.8", 53', 140° 経度: 32.8秒, 53分, 140度 (東経) [Reset format:ja]--------------------------------- Current format [eng]: {ref:u}: {seconds:v}{seconds:u}, {minutes:v}{minutes:u}, {degrees:v}{degrees:u} Current format [ja]: {ref:u}{degrees:v}{degrees:u}{minutes:v}{minutes:u}{seconds:v}{seconds:u} Latitude: N: 26.2", 3', 37° 緯度: 北緯37度3分26.2秒 Longitude: E: 32.8", 53', 140° 経度: 東経140度53分32.8秒
-
Get Format:
format()
-
Set Format:
format($format)
-
Reset Format:
resetFormat()
-
Default Format:
{ref:u}{degrees:v}{degrees:u}{minutes:v}{minutes:u}{seconds:v}{seconds:u}
-
Format-Tags:
Item Tag eng
ja
Ref {ref:u} N 北緯 Degrees Value {degrees:v} 12 12 Degrees Unit {degrees:u} ° 度 Minutes Value {minutes:v} 34 34 Minutes Unit {minutes:u} ' 分 Seconds Value {seconds:v} 56 56 Seconds Unit {seconds:u} " 秒 -
latitudeS()
andlongitudeS()
use common format.
for directionS()
, destBearingS()
and TrackS()
.
-
<?php require_once __DIR__ . '/../vendor/autoload.php'; use Macocci7\PhpPhotoGps\PhotoGps; $filename = 'img/with_gps.jpg'; $pg = new PhotoGps($filename); echo "[" . $filename . "]--------------------\n"; // Format: default echo "Current format [eng]: " . $pg->lang('eng')->directionFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->directionFormat() . "\n\n"; // Image Direction: default format echo "Image Direction [eng]: " . $pg->lang('eng')->directionS() . "\n"; echo "Image Direction [ja]: " . $pg->lang('ja')->directionS() . "\n\n"; // Configure Format: eng $pg->lang('eng')->directionFormat('{degrees:v}{degrees:u}({ref})'); // Current Format echo "Current format [eng]: " . $pg->lang('eng')->directionFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->directionFormat() . "\n\n"; // Image Direction: Current Format echo "Image Direction [eng]: " . $pg->lang('eng')->directionS() . "\n"; echo "Image Direction [ja]: " . $pg->lang('ja')->directionS() . "\n\n"; // Configure Format: ja $pg->lang('ja')->directionFormat('{degrees:v}{degrees:u}'); // Reset Format: eng $pg->lang('eng')->resetDirectionFormat(); // Current Format echo "Current format [eng]: " . $pg->lang('eng')->directionFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->directionFormat() . "\n\n"; // Image Direction: Current Format echo "Image Direction [eng]: " . $pg->lang('eng')->directionS() . "\n"; echo "Image Direction [ja]: " . $pg->lang('ja')->directionS() . "\n\n";
-
[img/with_gps.jpg]-------------------- Current format [eng]: {ref} {degrees:v}{degrees:u} Current format [ja]: {ref} {degrees:v}{degrees:u} Image Direction [eng]: T 306.25° Image Direction [ja]: 真北 306.25度 Current format [eng]: {degrees:v}{degrees:u}({ref}) Current format [ja]: {ref} {degrees:v}{degrees:u} Image Direction [eng]: 306.25°(T) Image Direction [ja]: 真北 306.25度 Current format [eng]: {ref} {degrees:v}{degrees:u} Current format [ja]: {degrees:v}{degrees:u} Image Direction [eng]: T 306.25° Image Direction [ja]: 306.25度
-
Get Format:
directionFormat()
-
Set Format:
directionFormat($format)
-
Reset Format:
resetDirectionFormat()
-
Default Format:
{ref} {degrees:v}{degrees:u}
-
Format-Tags:
Item Tag eng
ja
Ref {ref:u} T 真北 Degrees Value {degrees:v} 12.34 12.34 Degrees Unit {degrees:u} ° 度 -
directionS()
,destBearingS()
andTrackS()
use common format.
for speedS()
-
<?php require_once __DIR__ . '/../vendor/autoload.php'; use Macocci7\PhpPhotoGps\PhotoGps; $filename = 'img/with_gps.jpg'; $pg = new PhotoGps($filename); echo "[" . $filename . "]--------------------\n"; // Format: default echo "Current format [eng]: " . $pg->lang('eng')->speedFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->speedFormat() . "\n\n"; // Speed: default format echo "Speed [eng]: " . $pg->lang('eng')->speedS() . "\n"; echo "Speed [ja]: " . $pg->lang('ja')->speedS() . "\n\n"; // Configure Format: eng $pg->lang('eng')->speedFormat('{speed:v}({speed:u})'); // Current Format echo "Current format [eng]: " . $pg->lang('eng')->speedFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->speedFormat() . "\n\n"; // Speed: Current Format echo "Speed [eng]: " . $pg->lang('eng')->speedS() . "\n"; echo "Speed [ja]: " . $pg->lang('ja')->speedS() . "\n\n"; // Configure Format: ja $pg->lang('ja')->speedFormat('時速{speed:v}マイル'); // Reset Format: eng $pg->lang('eng')->resetSpeedFormat(); // Current Format echo "Current format [eng]: " . $pg->lang('eng')->speedFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->speedFormat() . "\n\n"; // Speed: Current Format echo "Speed [eng]: " . $pg->lang('eng')->speedS() . "\n"; echo "Speed [ja]: " . $pg->lang('ja')->speedS() . "\n\n";
-
[img/with_gps.jpg]-------------------- Current format [eng]: {speed:v}{speed:u} Current format [ja]: {speed:v}{speed:u} Speed [eng]: 1.60mph Speed [ja]: 1.60マイル/時 Current format [eng]: {speed:v}({speed:u}) Current format [ja]: {speed:v}{speed:u} Speed [eng]: 1.60(mph) Speed [ja]: 1.60マイル/時 Current format [eng]: {speed:v}{speed:u} Current format [ja]: 時速{speed:v}マイル Speed [eng]: 1.60mph Speed [ja]: 時速1.60マイル
-
Get Format:
speedFormat()
-
Set Format:
speedFormat($format)
-
Reset Format:
resetSpeedFormat()
-
Default Format:
{speed:v}{speed:u}
-
Format-Tags:
Item Tag eng
ja
Speed Value {speed:v} 12.34 12.34 Speed Unit {speed:u} km/h キロメートル/時
for datestamp()
-
<?php require_once __DIR__ . '/../vendor/autoload.php'; use Macocci7\PhpPhotoGps\PhotoGps; $filename = 'img/with_gps.jpg'; $pg = new PhotoGps($filename); echo "[" . $filename . "]--------------------\n"; // Format: default echo "Current format [eng]: " . $pg->lang('eng')->datestampFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->datestampFormat() . "\n\n"; // Datestamp: default format echo "Datestamp [eng]: " . $pg->lang('eng')->datestamp() . "\n"; echo "Datestamp [ja]: " . $pg->lang('ja')->datestamp() . "\n\n"; // Configure Format: eng $pg->lang('eng')->datestampFormat('l jS \of F Y'); // Current Format echo "Current format [eng]: " . $pg->lang('eng')->datestampFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->datestampFormat() . "\n\n"; // Datestamp: Current Format echo "Datestamp [eng]: " . $pg->lang('eng')->datestamp() . "\n"; echo "Datestamp [ja]: " . $pg->lang('ja')->datestamp() . "\n\n"; // Configure Format: ja $pg->lang('ja')->datestampFormat('n月j日(\'y)'); // Reset Format: eng $pg->lang('eng')->resetDatestampFormat(); // Current Format echo "Current format [eng]: " . $pg->lang('eng')->datestampFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->datestampFormat() . "\n\n"; // Datestamp: Current Format echo "Datestamp [eng]: " . $pg->lang('eng')->datestamp() . "\n"; echo "Datestamp [ja]: " . $pg->lang('ja')->datestamp() . "\n\n";
-
[img/with_gps.jpg]-------------------- Current format [eng]: Y/m/d Current format [ja]: Y年m月d日 Datestamp [eng]: 2023/09/18 Datestamp [ja]: 2023年09月18日 Current format [eng]: l jS \of F Y Current format [ja]: Y年m月d日 Datestamp [eng]: Monday 18th of September 2023 Datestamp [ja]: 2023年09月18日 Current format [eng]: Y/m/d Current format [ja]: n月j日('y) Datestamp [eng]: 2023/09/18 Datestamp [ja]: 9月18日('23)
- Get Format:
datestampFormat()
- Set Format:
datestampFormat($format)
- Reset Format:
resetDatestampFormat()
- Default Format:
eng
:Y/m/d
ja
:Y年m月d日
- Format parameter strings: See PHP Official
for timestamp()
-
<?php require_once __DIR__ . '/../vendor/autoload.php'; use Macocci7\PhpPhotoGps\PhotoGps; $filename = 'img/with_gps.jpg'; $pg = new PhotoGps($filename); echo "[" . $filename . "]--------------------\n"; // Format: default echo "Current format [eng]: " . $pg->lang('eng')->timestampFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->timestampFormat() . "\n\n"; // Timestamp: default format echo "Timestamp [eng]: " . $pg->lang('eng')->timestamp() . "\n"; echo "Timestamp [ja]: " . $pg->lang('ja')->timestamp() . "\n\n"; // Configure Format: eng $pg->lang('eng')->timestampFormat('g:i a'); // Current Format echo "Current format [eng]: " . $pg->lang('eng')->timestampFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->timestampFormat() . "\n\n"; // Timestamp: Current Format echo "Timestamp [eng]: " . $pg->lang('eng')->timestamp() . "\n"; echo "Timestamp [ja]: " . $pg->lang('ja')->timestamp() . "\n\n"; // Configure Format: ja $pg->lang('ja')->timestampFormat('G時i分s秒'); // Reset Format: eng $pg->lang('eng')->resetTimestampFormat(); // Current Format echo "Current format [eng]: " . $pg->lang('eng')->timestampFormat() . "\n"; echo "Current format [ja]: " . $pg->lang('ja')->timestampFormat() . "\n\n"; // Timestamp: Current Format echo "Timestamp [eng]: " . $pg->lang('eng')->timestamp() . "\n"; echo "Timestamp [ja]: " . $pg->lang('ja')->timestamp() . "\n\n";
-
[img/with_gps.jpg]-------------------- Current format [eng]: H:i:s Current format [ja]: H時i分s秒 Timestamp [eng]: 03:43:32 Timestamp [ja]: 03時43分32秒 Current format [eng]: g:i a Current format [ja]: H時i分s秒 Timestamp [eng]: 3:43 am Timestamp [ja]: 03時43分32秒 Current format [eng]: H:i:s Current format [ja]: G時i分s秒 Timestamp [eng]: 03:43:32 Timestamp [ja]: 3時43分32秒
- Get Format:
timestampFormat()
- Set Format:
timestampFormat($format)
- Reset Format:
resetTimestampFormat()
- Default Format:
eng
:H:i:s
ja
:H時i分s秒
- Format parameter strings: See PHP Official
Geo Data means latitude and longitude here.
The code below creates a list of photos in the dir img/
.
-
<?php require_once __DIR__ . '/../vendor/autoload.php'; use Macocci7\PhpPhotoGps\PhotoGps; $pg = new PhotoGps(); $images = glob('img/*.{jp*g,JP*G}', GLOB_BRACE); sort($images); echo "# Photo List: Geo Data\n\n"; echo "<table>\n"; echo "<tr><th>Image</th><th>Geo</th><th>Coordinate</th></tr>\n"; foreach ($images as $file) { $link = sprintf("<a href='%s'><img src='%s' width=100 /></a>", $file, $file); $pg->load($file); $hasGps = $pg->hasGps(); $hasGeo = $pg->hasGeo(); $hasAltitude = $pg->hasAltitude(); echo sprintf("<td>%s</td>", $link); echo sprintf("<td>%s</td>", $hasGps ? 'o' : 'x'); echo "<td>\n"; if ($hasGeo) { echo sprintf( "<a href='%s'>%s, %s</a><br />\n", sprintf( "https://www.google.com/maps/place/%s+%s/@%.7f,%.7f,17z/?authuser=0&entry=ttu", urlencode($pg->lang('eng')->latitudeS()), urlencode($pg->lang('eng')->longitudeS()), $pg->latitudeD(), $pg->longitudeD() ), sprintf("%.14f", $pg->latitudeD()), sprintf("%.14f", $pg->longitudeD()) ); foreach ($pg->langs() as $lang) { echo sprintf( "%s, %s<br />\n", $pg->lang($lang)->latitudeS(), $pg->lang($lang)->longitudeS() ); } } else { echo "No Geo Data\n\n"; } if ($hasAltitude) { foreach ($pg->langs() as $lang) { echo sprintf("%s\n\n", $pg->lang($lang)->altitudeS()); } } else { echo "No Altitude Data\n\n"; } echo "</td></tr>\n"; } echo "</table>\n";
-
Image Geo Coordinate o 31.53324552730697, 35.47923749904281
31°31'59.7"N, 35°28'45.3"E
北緯31度31分59.7秒, 東経35度28分45.3秒
(Below Sea Level) 422.00 m(負値海抜) 422.00 メートル
o -20.18913849132269, -67.58772465286874
20°11'20.9"S, 67°35'15.8"W
南緯20度11分20.9秒, 西経67度35分15.8秒
(Above Sea Level) 3700.00 m(正値海抜) 3700.00 メートル
o 35.87235861111111, 139.78356388888889
35°52'20.5"N, 139°47'0.8"E
北緯35度52分20.5秒, 東経139度47分0.8秒
(Above Ellipsoidal Surface) 3.70 m(正値楕円体高) 3.70 メートル
o 38.26386166666666, 140.87085083333335
38°15'49.9"N, 140°52'15.1"E
北緯38度15分49.9秒, 東経140度52分15.1秒
(Above Ellipsoidal Surface) 42.00 m(正値楕円体高) 42.00 メートル
o 37.05727416666667, 140.89244166666666
37°3'26.2"N, 140°53'32.8"E
北緯37度3分26.2秒, 東経140度53分32.8秒
(Above Ellipsoidal Surface) 13.00 m(正値楕円体高) 13.00 メートル
x No Geo Data No Altitude Data
- Load GPS Data from a photo:
load($path)
- Check If GPS Data Exists:
hasGps()
- Check If Geo Data Exists:
hasGeo()
- Check If Altitude Exists:
hasAltitude()
gps()
method returns all Exif tags which has GPS
prefix.
-
<?php require_once __DIR__ . '/../vendor/autoload.php'; use Macocci7\PhpPhotoGps\PhotoGps; use Macocci7\PhpPhotoGps\Helpers\Dir; use Macocci7\PhpPhotoGps\Helpers\Arrow; use Macocci7\PhpPhotoGps\Helpers\Exif; $pg = new PhotoGps(); $images = [ 'File with Fake GPS via HTTP' => 'http://macocci7.net/photo/gps/remote_fake_gps_001.jpg', 'File with Fake GPS via HTTPS' => 'https://macocci7.net/photo/gps/remote_fake_gps_002.jpg', 'Local File with GPS' => 'img/with_gps.jpg', 'No GPS tags' => 'img/without_gps.jpg', ]; $arrowSize = 30; Dir::clear('./download/'); echo "# Exif: GPS Tags\n\n"; // Loop for images foreach ($images as $title => $image) { echo "## $title\n\n"; // Start Table echo "<table>\n"; $style = 'display: flex; align-items: top;'; echo sprintf("<tr style='%s'>\n<td>\n", $style); // Thumbnail echo "<img src='$image' alt='$title' width='200'>\n\n"; // Load GPS Data $pg->load($image); // Show Attributes Converted from GPS Data $style = 'display: flex; justify-content: right; align-items: center;'; $direction = $pg->direction(); $speedS = $pg->speedS(); $track = $pg->track(); $destBearing = $pg->destBearing(); $datestamp = $pg->datestamp(); $timestamp = $pg->timestamp(); echo "|Attribute|Value|\n"; echo "|:---|---:|\n"; echo sprintf("|ExifVersion|%s|\n", Exif::version()); // Image Direction if (!is_null($direction)) { $pathArrow = sprintf('img/arrow%.2f.png', $direction); Arrow::make($direction)->save($pathArrow); echo sprintf( "|Image Direction|<div style='%s'><img src='%s' width=%d height=%d />%s</div>|\n", $style, $pathArrow, $arrowSize, $arrowSize, $pg->directionS() ); } // Speed if (!is_null($speedS)) { echo sprintf("|Speed|%s|\n", $speedS); } // Track if (!is_null($track)) { $pathArrow = sprintf('img/arrow%.2f.png', $track); Arrow::make($track)->save($pathArrow); echo sprintf( "|Track|<div style='%s'><img src='%s' width=%d height=%d />%s</div>|\n", $style, $pathArrow, $arrowSize, $arrowSize, $pg->trackS() ); } // Dest Bearing if (!is_null($destBearing)) { $pathArrow = sprintf('img/arrow%.2f.png', $destBearing); Arrow::make($destBearing)->save($pathArrow); echo sprintf( "|Destination Bearing|<div style='%s'><img src='%s' width=%d height=%d />%s</div>|\n", $style, $pathArrow, $arrowSize, $arrowSize, $pg->destBearingS() ); } // Date Stamp echo $datestamp ? sprintf("|Datestamp|%s (UTC)|\n", $datestamp) : ''; // Time Stamp echo $timestamp ? sprintf("|Timestamp|%s (UTC)|\n", $timestamp) : ''; echo "</td>\n<td>\n\n"; // Check If GPS Data Exists if ($pg->hasGps()) { // Show GPS Data echo "|Tag|Value|\n"; echo "|:---|---:|\n"; foreach ($pg->gps() as $tag => $value) { echo sprintf( "|%s|%s|\n", $tag, is_array($value) ? implode('<br />', $value) : $value ); } } else { echo "No GPS data.\n\n"; } // Close Table echo "</td>\n</tr>\n</table>\n\n"; }
-
Attribute Value ExifVersion 0300 Image Direction Speed 100.00mph Track Destination Bearing Datestamp 2015/06/07 (UTC) Timestamp 01:31:46 (UTC) Tag Value GPS_IFD_Pointer 214 GPSLatitudeRef S GPSLatitude 20/1
11/1
20898/1000GPSLongitudeRef W GPSLongitude 67/1
35/1
15808/1000GPSAltitudeRef 0 GPSAltitude 370000/100 GPSTimeStamp 1/1
31/1
46/1GPSSpeedRef M GPSSpeed 100/1 GPSTrackRef T GPSTrack 143885/536 GPSImgDirectionRef T GPSImgDirection 115074/413 GPSDestBearingRef T GPSDestBearing 188418/689 GPSDateStamp 2015:06:07 Attribute Value ExifVersion 0300 Image Direction Speed 1.60mph Track Datestamp 2023/09/18 (UTC) Timestamp 03:43:32 (UTC) Tag Value GPS_IFD_Pointer 908 GPSLatitudeRef N GPSLatitude 37/1
3/1
26187/1000GPSLongitudeRef E GPSLongitude 140/1
53/1
32790/1000GPSAltitudeRef 0 GPSAltitude 1300/100 GPSTimeStamp 3/1
43/1
32/1GPSSpeedRef M GPSSpeed 16/10 GPSTrackRef M GPSTrack 224936/625 GPSImgDirectionRef T GPSImgDirection 191409/625 GPSDateStamp 2023:09:18 Attribute Value ExifVersion 0220 No GPS data.
-
use
declaration:use Macocci7\PhpPhotoGps\Helpers\Dir;
to clear entries in
download
directory. -
use
declaration:use Macocci7\PhpPhotoGps\Helpers\Arrow;
to create arrow images.
-
Clear entries in a directory:
Dir::clear($dir)
-
Get Image Direction:
- As Float:
direction()
returnsnull
if not found. - As String:
directionS()
returnnull
if not found.
- As Float:
-
Get Speed:
- As Float:
speed()
returnsnull
if not found. - As String:
speedS()
returnsnull
if not found.
- As Float:
-
Get Track (Direction of Movement):
- As Float:
track()
returnsnull
if not found. - As String:
trackS()
returnsnull
if not found.
- As Float:
-
Get Destination Bearing:
- As Float:
destBearing()
returnsnull
if not found. - As String:
destBearingS()
returnsnull
if not found.
- As Float:
-
Get Date Stamp:
datestamp()
returnsnull
if not found. -
Get Time Stamp:
timestamp()
returnsnull
if not found. -
Create Arrow Image:
Arrow::make($degree)->save($pathArrow)
-
$degree
: must be in clockwise degrees. (0° ~ 360°) -
Arrow:make()
: returns the instance ofIntervention\Image\Interfaces\ImageInterface
(v3.3) -
Returning HTTP Response with it is available. -
See more: Intervention/image Official Documentresponse()
has removed since v3. -
Note:
- If the reference is 'M' (Magnetic North), the arrow image shows the relative direction from Magnetic North(Magnetic North upward).
- Magnetic North pole moves over time. See more.
-
-
Note:
- All photos in this repository were taken by macocci7 with mobile phone, and free to use.
- Some of GPS data was manually injected with some tools.
-
GIMP v2.10.34 used for:
GPSLatitudeRef
GPSLatitude
GPSLongitudeRef
GPSLongitude
GPSAltitudeRef
GPSAltitude
GIMP can edit only geo tags.
-
Exif Tool by Phil Harvey v12.72 used for:
- All other GPS tags
Exif Tool can edit all writable GPS tags.
However, Exif Tool currently cannot set
GPSSpeedRef
asK
(maybe a bug).
-
-
<?php require_once __DIR__ . '/../vendor/autoload.php'; use Macocci7\PhpPhotoGps\Helpers\Gps; //$exifVersion = "0210"; //$exifVersion = "0220"; //$exifVersion = "0221"; //$exifVersion = "0230"; //$exifVersion = "0231"; //$exifVersion = "0232"; $exifVersion = "0300"; echo "# Exif" . $exifVersion . ": GPS Attribute Information\n\n"; echo "|Field Name|Type|Count|Values|Default|Separator|\n"; echo "|:---|:---|---:|:---|:---:|:---:|\n"; foreach (Gps::def('exif' . $exifVersion . '.fields') as $key => $value) { echo sprintf( "|%s|%s|%d|%s|%s|%s|\n", $key, $value['type'], $value['count'], isset($value['values']) ? implode( '<br />', array_map( fn ($k, $v) => '* ' . $k . ': ' . $v, array_keys($value['values']), $value['values'] ) ) : '---', $value['default'] ?? '---', $value['separator'] ?? '---' ); }
-
Field Name Type Count Values Default Separator GPSVersion BYTE 4 --- 2.4.0.0 . GPSVersionID BYTE 4 --- 2.4.0.0 . GPSLatitudeRef ASCII 2 * N: North latitude
* S: South latitudeNone --- GPSLatitude RATIONAL 3 --- None --- GPSLongitudeRef ASCII 2 * E: East longitude
* W: West longitudeNone --- GPSLongitude RATIONAL 3 --- None --- GPSAltitudeRef BYTE 1 * 0: Positive ellipsoidal height (at or above ellipsoidal surface)
* 1: Negative ellipsoid height (below ellipsoidal surface)
* 2: Positive sea level value (at or above sea level reference)
* 3: Negative sea level value (below sea level reference)0 GPSAltitude RATIONAL 1 --- None --- GPSTimeStamp RATIONAL 3 --- None --- GPSSatellites ASCII 0 --- None --- GPSStatus ASCII 2 * A: Measurement in progress
* V: Measurement interruptedNone --- GPSMeasureMode ASCII 2 * 2: 2-dimensional measurement
* 3: 3-dimensional measurementNone --- GPSDOP RATIONAL 1 --- None --- GPSSpeedRef ASCII 2 * K: Kilometers per hour
* M: Miles per hour
* N: KnotsK --- GPSSpeed RATIONAL 1 --- None --- GPSTrackRef ASCII 2 * T: True direction
* M: Magnetic directionT --- GPSTrack RATIONAL 1 --- None --- GPSImgDirectionRef ASCII 2 * T: True direction
* M: Magnetic directionT --- GPSImgDirection RATIONAL 1 --- None --- GPSMapDatum ASCII 0 --- None --- GPSDestLatitudeRef ASCII 2 * N: North latitude
* S: South latitudeNone --- GPSDestLatitude RATIONAL 3 --- None --- GPSDestLongitudeRef ASCII 2 * E: East longitude
* W: West longitudeNone --- GPSDestLongitude RATIONAL 3 --- None --- GPSDestBearingRef ASCII 2 * T: True direction
* M: Magnetic directionT --- GPSDestBearing RATIONAL 1 --- None --- GPSDestDistanceRef ASCII 2 * K: Kilometers
* M: Miles
* N: Nautical milesK --- GPSDestDistance RATIONAL 1 --- None --- GPSProcessingMethod UNDEFINED 0 * GPS: GPS [GPSMeaMeasureMode: 2 or 3]
* QZSS: Quasi-Zenith Satellite System [GPSMeasureMode: 2 or 3]
* GALILEO: Galileo System [GPSMeasureMode: 2 or 3]
* GLONASS: Global Navigation Satellite System [GPSMeasureMode: 2 or 3]
* BEIDOU: Beidou Satellite Positioning System [GPSMeasureMode: 2 or 3]
* NAVID: Navigation Indian Constellation System [GPSMeasureMode: 2 or 3]
* CELLID: Mobile Phone Base Stations [GPSMeasureMode: 2 (generally)]
* WLAN: Wireless LAN [GPSMeasureMode: 2 (generally)]
* MANUAL: Manual input [GPSMeasureMode: (not recorded)]None --- GPSAreaInformation UNDEFINED 0 --- None --- GPSDateStamp ASCII 11 --- None --- GPSDifferential SHORT 1 * 0: Measurement without differential correction
* 1: Differential correction appliedNone --- GPSHPositioningError RATIONAL 1 --- None ---
-
use
declaration:use Macocci7\PhpPhotoGps\Helpers\Gps;
to use GPS Data Interface.
-
Get GPS Tag Attributes:
Gps::def()
orGps::def($tagName)
it returns
null
if not found.GPS Tag Attributes are defined in
config/Gps.neon
.The structure of Hash array returned by
Gps::def()
is as below:exifXXXX
:XXXX
is replaced with Exif Version number.fields
:- TagName: like
GPSVersionID
orGPSAltitude
type
: based on Exif Standardcount
: based on Exif Standarddefault
: based on Exif Standardvalues
: based on Exif Standardseparator
: originaly added
- TagName: like
Object-like dot-separated specifiers are available for
$tagName
.For example,
Gps::def('exif0300.fields.GPSLatitudeRef')
returns:[ 'type' => 'ASCII', 'count' => 2, 'default' => 'None' 'values' => [ 'N' => 'North latitude', 'S' => 'South latitude', ], ];
- BasicUsage.php >> results in BasicUsage.txt
- CheckGeoData.php >> results in CheckGeoData.md
- ConfigFormat.php >> results in ConfigFormat.txt
- ConfigDirectionFormat.php >> results in ConfigDirectionFormat.txt
- ConfigSpeedFormat.php >> results in ConfigSpeedFormat.txt
- ReadAllGpsTags.php >> results in ReadAllGpsTags.md
- GpsAttrInfo.php >> results in GpsAttrInfo.md
Document created: 2023/09/30
Document updated: 2024/10/02
Copyright 2023 - 2024 macocci7