@@ -71,14 +71,18 @@ class Native extends AdapterAbstract
71
71
* @var array
72
72
*/
73
73
protected $ iptcMapping = array (
74
- 'title ' => '2#005 ' ,
75
- 'keywords ' => '2#025 ' ,
76
- 'copyright ' => '2#116 ' ,
77
- 'caption ' => '2#120 ' ,
78
- 'headline ' => '2#105 ' ,
79
- 'credit ' => '2#110 ' ,
80
- 'source ' => '2#115 ' ,
81
- 'jobtitle ' => '2#085 '
74
+ 'title ' => '2#005 ' ,
75
+ 'keywords ' => '2#025 ' ,
76
+ 'copyright ' => '2#116 ' ,
77
+ 'caption ' => '2#120 ' ,
78
+ 'headline ' => '2#105 ' ,
79
+ 'credit ' => '2#110 ' ,
80
+ 'source ' => '2#115 ' ,
81
+ 'jobtitle ' => '2#085 ' ,
82
+ 'city ' => '2#090 ' ,
83
+ 'sublocation ' => '2#092 ' ,
84
+ 'state ' => '2#095 ' ,
85
+ 'country ' => '2#101 '
82
86
);
83
87
84
88
@@ -176,38 +180,27 @@ public function getExifFromFile($file)
176
180
{
177
181
$ mimeType = mime_content_type ($ file );
178
182
179
- if (strpos ($ mimeType , 'video ' ) !== 0 ) {
180
183
181
- // Photo
182
- $ sections = $ this ->getRequiredSections ();
183
- $ sections = implode (', ' , $ sections );
184
- $ sections = (empty ($ sections )) ? null : $ sections ;
185
184
186
- $ data = @exif_read_data (
187
- $ file ,
188
- $ sections ,
189
- $ this ->getSectionsAsArrays (),
190
- $ this ->getIncludeThumbnail ()
191
- );
185
+ // Photo
186
+ $ sections = $ this ->getRequiredSections ();
187
+ $ sections = implode (', ' , $ sections );
188
+ $ sections = (empty ($ sections )) ? null : $ sections ;
192
189
193
- if (false === $ data ) {
194
- return false ;
195
- }
190
+ $ data = @exif_read_data (
191
+ $ file ,
192
+ $ sections ,
193
+ $ this ->getSectionsAsArrays (),
194
+ $ this ->getIncludeThumbnail ()
195
+ );
196
196
197
- $ xmpData = $ this ->getIptcData ($ file );
198
- $ data = array_merge ($ data , array (self ::SECTION_IPTC => $ xmpData ));
199
-
200
- } else {
201
- // Video
202
- try {
197
+ if (false === $ data ) {
198
+ return false ;
199
+ }
203
200
204
- $ data = $ this ->getVideoData ($ file );
205
- $ data[ ' MimeType ' ] = $ mimeType ;
201
+ $ xmpData = $ this ->getIptcData ($ file );
202
+ $ data = array_merge ( $ data, array ( self :: SECTION_IPTC => $ xmpData )) ;
206
203
207
- } catch (Exception $ exception ) {
208
- Logs::error (__METHOD__ , __LINE__ , $ exception ->getMessage ());
209
- }
210
- }
211
204
212
205
// map the data:
213
206
$ mapper = $ this ->getMapper ();
@@ -222,163 +215,6 @@ public function getExifFromFile($file)
222
215
return $ exif ;
223
216
}
224
217
225
- /**
226
- * Returns an array of video data
227
- *
228
- * @param string $file The file to read the video data from
229
- * @return array
230
- */
231
- public function getVideoData ($ filename )
232
- {
233
-
234
- $ metadata ['FileSize ' ] = filesize ($ filename );
235
-
236
- $ path_ffmpeg = exec ('which ffmpeg ' );
237
- $ path_ffprobe = exec ('which ffprobe ' );
238
- $ ffprobe = FFMpeg \FFProbe::create (array (
239
- 'ffmpeg.binaries ' => $ path_ffmpeg ,
240
- 'ffprobe.binaries ' => $ path_ffprobe ,
241
- ));
242
-
243
- $ stream = $ ffprobe ->streams ($ filename )->videos ()->first ()->all ();
244
- $ format = $ ffprobe ->format ($ filename )->all ();
245
- if (isset ($ stream ['width ' ])) {
246
- $ metadata ['Width ' ] = $ stream ['width ' ];
247
- }
248
- if (isset ($ stream ['height ' ])) {
249
- $ metadata ['Height ' ] = $ stream ['height ' ];
250
- }
251
- if (isset ($ stream ['tags ' ]) && isset ($ stream ['tags ' ]['rotate ' ]) && ($ stream ['tags ' ]['rotate ' ] === '90 ' || $ stream ['tags ' ]['rotate ' ] === '270 ' )) {
252
- $ tmp = $ metadata ['Width ' ];
253
- $ metadata ['Width ' ] = $ metadata ['Height ' ];
254
- $ metadata ['Height ' ] = $ tmp ;
255
- }
256
- if (isset ($ stream ['avg_frame_rate ' ])) {
257
- $ framerate = explode ('/ ' , $ stream ['avg_frame_rate ' ]);
258
- if (count ($ framerate ) == 1 ) {
259
- $ framerate = $ framerate [0 ];
260
- } elseif (count ($ framerate ) == 2 && $ framerate [1 ] != 0 ) {
261
- $ framerate = number_format ($ framerate [0 ] / $ framerate [1 ], 3 );
262
- } else {
263
- $ framerate = '' ;
264
- }
265
- if ($ framerate !== '' ) {
266
- $ metadata ['framerate ' ] = $ framerate ;
267
- }
268
- }
269
- if (isset ($ format ['duration ' ])) {
270
- $ metadata ['duration ' ] = number_format ($ format ['duration ' ], 3 );
271
- }
272
- if (isset ($ format ['tags ' ])) {
273
- if (isset ($ format ['tags ' ]['creation_time ' ]) && strtotime ($ format ['tags ' ]['creation_time ' ]) !== 0 ) {
274
- $ metadata ['DateTimeOriginal ' ] = date ('Y-m-d H:i:s ' , strtotime ($ format ['tags ' ]['creation_time ' ]));
275
- }
276
- if (isset ($ format ['tags ' ]['location ' ])) {
277
- $ matches = [];
278
- preg_match ('/^([+-][0-9\.]+)([+-][0-9\.]+)\/$/ ' , $ format ['tags ' ]['location ' ], $ matches );
279
- if (count ($ matches ) == 3 &&
280
- !preg_match ('/^\+0+\.0+$/ ' , $ matches [1 ]) &&
281
- !preg_match ('/^\+0+\.0+$/ ' , $ matches [2 ])) {
282
- $ metadata ['GPSLatitude ' ] = $ matches [1 ];
283
- $ metadata ['GPSLongitude ' ] = $ matches [2 ];
284
- }
285
- }
286
- // QuickTime File Format defines several additional metadata
287
- // Source: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/Metadata/Metadata.html
288
- // Special case: iPhones write into tags->creation_time the creation time of the file
289
- // -> When converting the video from HEVC (iOS Video format) to MOV, the creation_time
290
- // is the time when the mov file was created, not when the video was shot (fixed in iOS12)
291
- // (see e.g. https://michaelkummer.com/tech/apple/photos-videos-wrong-date/ (for the symptom)
292
- // Solution: Use com.apple.quicktime.creationdate which is the true creation date of the video
293
- if (isset ($ format ['tags ' ]['com.apple.quicktime.creationdate ' ])) {
294
- $ metadata ['DateTimeOriginal ' ] = date ('Y-m-d H:i:s ' , strtotime ($ format ['tags ' ]['com.apple.quicktime.creationdate ' ]));
295
- }
296
- if (isset ($ format ['tags ' ]['com.apple.quicktime.description ' ])) {
297
- $ metadata ['description ' ] = $ format ['tags ' ]['com.apple.quicktime.description ' ];
298
- }
299
- if (isset ($ format ['tags ' ]['com.apple.quicktime.title ' ])) {
300
- $ metadata ['title ' ] = $ format ['tags ' ]['com.apple.quicktime.title ' ];
301
- }
302
- if (isset ($ format ['tags ' ]['com.apple.quicktime.keywords ' ])) {
303
- $ metadata ['keywords ' ] = $ format ['tags ' ]['com.apple.quicktime.keywords ' ];
304
- }
305
- if (isset ($ format ['tags ' ]['com.apple.quicktime.location.ISO6709 ' ])) {
306
- $ location_data = $ this ->readISO6709 ($ format ['tags ' ]['com.apple.quicktime.location.ISO6709 ' ]);
307
- $ metadata ['GPSLatitude ' ] = $ location_data ['latitude ' ];
308
- $ metadata ['GPSLongitude ' ] = $ location_data ['longitude ' ];
309
- $ metadata ['GPSAltitude ' ] = $ location_data ['altitude ' ];
310
- }
311
- // Not documented, but available on iPhone videos
312
- if (isset ($ format ['tags ' ]['com.apple.quicktime.make ' ])) {
313
- $ metadata ['Make ' ] = $ format ['tags ' ]['com.apple.quicktime.make ' ];
314
- }
315
- // Not documented, but available on iPhone videos
316
- if (isset ($ format ['tags ' ]['com.apple.quicktime.model ' ])) {
317
- $ metadata ['Model ' ] = $ format ['tags ' ]['com.apple.quicktime.model ' ];
318
- }
319
- }
320
-
321
- return $ metadata ;
322
- }
323
-
324
- /**
325
- * Converts results of ISO6709 parsing
326
- * to decimal format for latitude and longitude
327
- * See https://github.com/seanson/python-iso6709.git.
328
- *
329
- * @param string sign
330
- * @param string degrees
331
- * @param string minutes
332
- * @param string seconds
333
- * @param string fraction
334
- *
335
- * @return float
336
- */
337
- private function convertDMStoDecimal (string $ sign , string $ degrees , string $ minutes , string $ seconds , string $ fraction ): float
338
- {
339
- if ($ fraction !== '' ) {
340
- if ($ seconds !== '' ) {
341
- $ seconds = $ seconds . $ fraction ;
342
- } elseif ($ minutes !== '' ) {
343
- $ minutes = $ minutes . $ fraction ;
344
- } else {
345
- $ degrees = $ degrees . $ fraction ;
346
- }
347
- }
348
- $ decimal = floatval ($ degrees ) + floatval ($ minutes ) / 60.0 + floatval ($ seconds ) / 3600.0 ;
349
- if ($ sign == '- ' ) {
350
- $ decimal = -1.0 * $ decimal ;
351
- }
352
- return $ decimal ;
353
- }
354
-
355
- /**
356
- * Returns the latitude, longitude and altitude
357
- * of a GPS coordiante formattet with ISO6709
358
- * See https://github.com/seanson/python-iso6709.git.
359
- *
360
- * @param string val_ISO6709
361
- *
362
- * @return array
363
- */
364
- private function readISO6709 (string $ val_ISO6709 ): array
365
- {
366
- $ return = [
367
- 'latitude ' => null ,
368
- 'longitude ' => null ,
369
- 'altitude ' => null ,
370
- ];
371
- $ matches = [];
372
- // Adjustment compared to https://github.com/seanson/python-iso6709.git
373
- // Altitude have format +XX.XXXX -> Adjustment for decimal
374
- preg_match ('/^(?<lat_sign>\+|-)(?<lat_degrees>[0,1]?\d{2})(?<lat_minutes>\d{2}?)?(?<lat_seconds>\d{2}?)?(?<lat_fraction>\.\d+)?(?<lng_sign>\+|-)(?<lng_degrees>[0,1]?\d{2})(?<lng_minutes>\d{2}?)?(?<lng_seconds>\d{2}?)?(?<lng_fraction>\.\d+)?(?<alt>[\+\-][0-9]\d*(\.\d+)?)?\/$/ ' , $ val_ISO6709 , $ matches );
375
- $ return ['latitude ' ] = $ this ->convertDMStoDecimal ($ matches ['lat_sign ' ], $ matches ['lat_degrees ' ], $ matches ['lat_minutes ' ], $ matches ['lat_seconds ' ], $ matches ['lat_fraction ' ]);
376
- $ return ['longitude ' ] = $ this ->convertDMStoDecimal ($ matches ['lng_sign ' ], $ matches ['lng_degrees ' ], $ matches ['lng_minutes ' ], $ matches ['lng_seconds ' ], $ matches ['lng_fraction ' ]);
377
- if (isset ($ matches ['alt ' ])) {
378
- $ return ['altitude ' ] = doubleval ($ matches ['alt ' ]);
379
- }
380
- return $ return ;
381
- }
382
218
383
219
/**
384
220
* Returns an array of IPTC data
0 commit comments