Skip to content

Commit 458a373

Browse files
committed
Extract GPS data from EXIF
Signed-off-by: Louis Chemineau <louis@chmn.me>
1 parent 232866d commit 458a373

File tree

1 file changed

+62
-13
lines changed

1 file changed

+62
-13
lines changed

lib/private/Metadata/Provider/ExifProvider.php

+62-13
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,23 @@ public static function isAvailable(): bool {
1616
}
1717

1818
public function execute(File $file): array {
19+
$exifData = [];
1920
$fileDescriptor = $file->fopen('rb');
20-
$data = exif_read_data($fileDescriptor, 'COMPUTED', true);
21+
22+
// Copy image data into tmp stream as exif_read_data don't work properly with our streams wrappers.
23+
$nativeFileDescriptorStream = fopen('php://temp', 'rw');
24+
$result = stream_copy_to_stream(
25+
$fileDescriptor,
26+
$nativeFileDescriptorStream,
27+
);
28+
29+
if ($result === false) {
30+
fclose($nativeFileDescriptorStream);
31+
throw new \Exception("Failed to copy into tmp stream from fileid: " . $file->getId());
32+
}
33+
34+
$data = exif_read_data($nativeFileDescriptorStream, 'ANY_TAG', true);
35+
fclose($nativeFileDescriptorStream);
2136

2237
$size = new FileMetadata();
2338
$size->setGroupName('size');
@@ -31,29 +46,63 @@ public function execute(File $file): array {
3146
'width' => $sizeResult[0],
3247
'height' => $sizeResult[1],
3348
]);
49+
50+
$exifData['size'] = $size;
3451
}
3552

36-
return [
37-
'size' => $size,
38-
];
53+
} elseif (array_key_exists('COMPUTED', $data)) {
54+
if (array_key_exists('Width', $data['COMPUTED']) && array_key_exists('Height', $data['COMPUTED'])) {
55+
$size->setMetadata([
56+
'width' => $data['COMPUTED']['Width'],
57+
'height' => $data['COMPUTED']['Height'],
58+
]);
59+
60+
$exifData['size'] = $size;
61+
}
3962
}
4063

41-
if (array_key_exists('COMPUTED', $data)
42-
&& array_key_exists('Width', $data['COMPUTED'])
43-
&& array_key_exists('Height', $data['COMPUTED'])
64+
if ($data && array_key_exists('GPS', $data)
65+
&& array_key_exists('GPSLatitude', $data['GPS']) && array_key_exists('GPSLatitudeRef', $data['GPS'])
66+
&& array_key_exists('GPSLongitude', $data['GPS']) && array_key_exists('GPSLongitudeRef', $data['GPS'])
4467
) {
45-
$size->setMetadata([
46-
'width' => $data['COMPUTED']['Width'],
47-
'height' => $data['COMPUTED']['Height'],
68+
$gps = new FileMetadata();
69+
$gps->setGroupName('gps');
70+
$gps->setId($file->getId());
71+
$gps->setMetadata([
72+
'coordinate' => [
73+
'latitude' => $this->gpsDegreesToDecimal($data['GPS']['GPSLatitude'], $data['GPS']['GPSLatitudeRef']),
74+
'longitude' => $this->gpsDegreesToDecimal($data['GPS']['GPSLongitude'], $data['GPS']['GPSLongitudeRef']),
75+
],
4876
]);
77+
78+
$exifData['gps'] = $gps;
4979
}
5080

51-
return [
52-
'size' => $size,
53-
];
81+
return $exifData;
5482
}
5583

5684
public static function getMimetypesSupported(): string {
5785
return '/image\/.*/';
5886
}
87+
88+
/**
89+
* @param array|string $coordinate
90+
*/
91+
private static function gpsDegreesToDecimal(array $coordinates, string $hemisphere): float {
92+
if (is_string($coordinates)) {
93+
$coordinates = array_map("trim", explode(",", $coordinates));
94+
}
95+
96+
if (count($coordinates) !== 3) {
97+
throw new \Exception('Invalid coordinate format: ' . $coordinates);
98+
}
99+
100+
[$degrees, $minutes, $seconds] = array_map(function (string $rawDegree) {
101+
$parts = explode('/', $rawDegree);
102+
return floatval($parts[0])/floatval($parts[1] ?? 1);
103+
}, $coordinates);
104+
105+
$sign = ($hemisphere === 'W' || $hemisphere === 'S') ? -1 : 1;
106+
return $sign * ($degrees + $minutes/60 + $seconds/3600);
107+
}
59108
}

0 commit comments

Comments
 (0)