211 lines
7.8 KiB
PHP
211 lines
7.8 KiB
PHP
<?php
|
|
/**
|
|
* PHP Exif Exiftool Mapper
|
|
*
|
|
* @link http://github.com/miljar/PHPExif for the canonical source repository
|
|
* @copyright Copyright (c) 2015 Tom Van Herreweghe <tom@theanalogguy.be>
|
|
* @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License
|
|
* @category PHPExif
|
|
* @package Mapper
|
|
*/
|
|
|
|
namespace PHPExif\Mapper;
|
|
|
|
use PHPExif\Exif;
|
|
use DateTime;
|
|
|
|
/**
|
|
* PHP Exif Exiftool Mapper
|
|
*
|
|
* Maps Exiftool raw data to valid data for the \PHPExif\Exif class
|
|
*
|
|
* @category PHPExif
|
|
* @package Mapper
|
|
*/
|
|
class Exiftool implements MapperInterface
|
|
{
|
|
const APERTURE = 'Composite:Aperture';
|
|
const APPROXIMATEFOCUSDISTANCE = 'XMP-aux:ApproximateFocusDistance';
|
|
const ARTIST = 'IFD0:Artist';
|
|
const CAPTION = 'XMP-acdsee';
|
|
const CAPTIONABSTRACT = 'IPTC:Caption-Abstract';
|
|
const COLORSPACE = 'ExifIFD:ColorSpace';
|
|
const COPYRIGHT = 'IFD0:Copyright';
|
|
const DATETIMEORIGINAL = 'ExifIFD:DateTimeOriginal';
|
|
const CREDIT = 'IPTC:Credit';
|
|
const EXPOSURETIME = 'ExifIFD:ExposureTime';
|
|
const FILESIZE = 'System:FileSize';
|
|
const FOCALLENGTH = 'ExifIFD:FocalLength';
|
|
const HEADLINE = 'IPTC:Headline';
|
|
const IMAGEHEIGHT = 'File:ImageHeight';
|
|
const IMAGEWIDTH = 'File:ImageWidth';
|
|
const ISO = 'ExifIFD:ISO';
|
|
const JOBTITLE = 'IPTC:By-lineTitle';
|
|
const KEYWORDS = 'IPTC:Keywords';
|
|
const MIMETYPE = 'File:MIMEType';
|
|
const MODEL = 'IFD0:Model';
|
|
const ORIENTATION = 'IFD0:Orientation';
|
|
const SOFTWARE = 'IFD0:Software';
|
|
const SOURCE = 'IPTC:Source';
|
|
const TITLE = 'IPTC:ObjectName';
|
|
const XRESOLUTION = 'IFD0:XResolution';
|
|
const YRESOLUTION = 'IFD0:YResolution';
|
|
const GPSLATITUDE = 'GPS:GPSLatitude';
|
|
const GPSLONGITUDE = 'GPS:GPSLongitude';
|
|
|
|
/**
|
|
* Maps the ExifTool fields to the fields of
|
|
* the \PHPExif\Exif class
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $map = array(
|
|
self::APERTURE => Exif::APERTURE,
|
|
self::ARTIST => Exif::AUTHOR,
|
|
self::MODEL => Exif::CAMERA,
|
|
self::CAPTION => Exif::CAPTION,
|
|
self::COLORSPACE => Exif::COLORSPACE,
|
|
self::COPYRIGHT => Exif::COPYRIGHT,
|
|
self::DATETIMEORIGINAL => Exif::CREATION_DATE,
|
|
self::CREDIT => Exif::CREDIT,
|
|
self::EXPOSURETIME => Exif::EXPOSURE,
|
|
self::FILESIZE => Exif::FILESIZE,
|
|
self::FOCALLENGTH => Exif::FOCAL_LENGTH,
|
|
self::APPROXIMATEFOCUSDISTANCE => Exif::FOCAL_DISTANCE,
|
|
self::HEADLINE => Exif::HEADLINE,
|
|
self::IMAGEHEIGHT => Exif::HEIGHT,
|
|
self::XRESOLUTION => Exif::HORIZONTAL_RESOLUTION,
|
|
self::ISO => Exif::ISO,
|
|
self::JOBTITLE => Exif::JOB_TITLE,
|
|
self::KEYWORDS => Exif::KEYWORDS,
|
|
self::MIMETYPE => Exif::MIMETYPE,
|
|
self::ORIENTATION => Exif::ORIENTATION,
|
|
self::SOFTWARE => Exif::SOFTWARE,
|
|
self::SOURCE => Exif::SOURCE,
|
|
self::TITLE => Exif::TITLE,
|
|
self::YRESOLUTION => Exif::VERTICAL_RESOLUTION,
|
|
self::IMAGEWIDTH => Exif::WIDTH,
|
|
self::CAPTIONABSTRACT => Exif::CAPTION,
|
|
self::GPSLATITUDE => Exif::GPS,
|
|
self::GPSLONGITUDE => Exif::GPS,
|
|
);
|
|
|
|
/**
|
|
* @var bool
|
|
*/
|
|
protected $numeric = true;
|
|
|
|
/**
|
|
* Mutator method for the numeric property
|
|
*
|
|
* @param bool $numeric
|
|
* @return \PHPExif\Mapper\Exiftool
|
|
*/
|
|
public function setNumeric($numeric)
|
|
{
|
|
$this->numeric = (bool) $numeric;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Maps the array of raw source data to the correct
|
|
* fields for the \PHPExif\Exif class
|
|
*
|
|
* @param array $data
|
|
* @return array
|
|
*/
|
|
public function mapRawData(array $data)
|
|
{
|
|
$mappedData = array();
|
|
$gpsData = array();
|
|
foreach ($data as $field => $value) {
|
|
if (!array_key_exists($field, $this->map)) {
|
|
// silently ignore unknown fields
|
|
continue;
|
|
}
|
|
|
|
$key = $this->map[$field];
|
|
|
|
// manipulate the value if necessary
|
|
switch ($field) {
|
|
case self::APERTURE:
|
|
$value = sprintf('f/%01.1f', $value);
|
|
break;
|
|
case self::APPROXIMATEFOCUSDISTANCE:
|
|
$value = sprintf('%1$sm', $value);
|
|
break;
|
|
case self::DATETIMEORIGINAL:
|
|
try {
|
|
$value = new DateTime($value);
|
|
} catch (\Exception $exception) {
|
|
continue 2;
|
|
}
|
|
break;
|
|
case self::EXPOSURETIME:
|
|
// Based on the source code of Exiftool (PrintExposureTime subroutine):
|
|
// http://cpansearch.perl.org/src/EXIFTOOL/Image-ExifTool-9.90/lib/Image/ExifTool/Exif.pm
|
|
if ($value < 0.25001 && $value > 0) {
|
|
$value = sprintf('1/%d', intval(0.5 + 1 / $value));
|
|
} else {
|
|
$value = sprintf('%.1f', $value);
|
|
$value = preg_replace('/.0$/', '', $value);
|
|
}
|
|
break;
|
|
case self::FOCALLENGTH:
|
|
if (!$this->numeric || strpos($value, ' ') !== false) {
|
|
$focalLengthParts = explode(' ', $value);
|
|
$value = reset($focalLengthParts);
|
|
}
|
|
break;
|
|
case self::GPSLATITUDE:
|
|
$gpsData['lat'] = $this->extractGPSCoordinates($value);
|
|
break;
|
|
case self::GPSLONGITUDE:
|
|
$gpsData['lon'] = $this->extractGPSCoordinates($value);
|
|
break;
|
|
}
|
|
|
|
// set end result
|
|
$mappedData[$key] = $value;
|
|
}
|
|
|
|
// add GPS coordinates, if available
|
|
if (count($gpsData) === 2 && $gpsData['lat'] !== false && $gpsData['lon'] !== false) {
|
|
$latitudeRef = empty($data['GPS:GPSLatitudeRef'][0]) ? 'N' : $data['GPS:GPSLatitudeRef'][0];
|
|
$longitudeRef = empty($data['GPS:GPSLongitudeRef'][0]) ? 'E' : $data['GPS:GPSLongitudeRef'][0];
|
|
|
|
$gpsLocation = sprintf(
|
|
'%s,%s',
|
|
(strtoupper($latitudeRef) === 'S' ? -1 : 1) * $gpsData['lat'],
|
|
(strtoupper($longitudeRef) === 'W' ? -1 : 1) * $gpsData['lon']
|
|
);
|
|
|
|
$mappedData[Exif::GPS] = $gpsLocation;
|
|
} else {
|
|
unset($mappedData[Exif::GPS]);
|
|
}
|
|
|
|
return $mappedData;
|
|
}
|
|
|
|
/**
|
|
* Extract GPS coordinates from formatted string
|
|
*
|
|
* @param string $coordinates
|
|
* @return array
|
|
*/
|
|
protected function extractGPSCoordinates($coordinates)
|
|
{
|
|
if ($this->numeric === true) {
|
|
return abs((float) $coordinates);
|
|
} else {
|
|
if (!preg_match('!^([0-9.]+) deg ([0-9.]+)\' ([0-9.]+)"!', $coordinates, $matches)) {
|
|
return false;
|
|
}
|
|
|
|
return floatval($matches[1]) + (floatval($matches[2]) / 60) + (floatval($matches[3]) / 3600);
|
|
}
|
|
}
|
|
}
|