first commit

This commit is contained in:
root
2020-02-19 16:42:35 +01:00
commit d668d90f82
2224 changed files with 334338 additions and 0 deletions

View File

@ -0,0 +1,210 @@
<?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);
}
}
}

View File

@ -0,0 +1,33 @@
<?php
/**
* PHP Exif Mapper Interface: Defines the interface for data mappers
*
* @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
* @codeCoverageIgnore
*/
namespace PHPExif\Mapper;
/**
* PHP Exif Mapper
*
* Defines the interface for data mappers
*
* @category PHPExif
* @package Mapper
*/
interface MapperInterface
{
/**
* 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);
}

View File

@ -0,0 +1,289 @@
<?php
/**
* PHP Exif Native 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;
use Exception;
/**
* PHP Exif Native Mapper
*
* Maps native raw data to valid data for the \PHPExif\Exif class
*
* @category PHPExif
* @package Mapper
*/
class Native implements MapperInterface
{
const APERTUREFNUMBER = 'ApertureFNumber';
const ARTIST = 'Artist';
const CAPTION = 'caption';
const COLORSPACE = 'ColorSpace';
const COPYRIGHT = 'copyright';
const DATETIMEORIGINAL = 'DateTimeOriginal';
const CREDIT = 'credit';
const EXPOSURETIME = 'ExposureTime';
const FILESIZE = 'FileSize';
const FOCALLENGTH = 'FocalLength';
const FOCUSDISTANCE = 'FocusDistance';
const HEADLINE = 'headline';
const HEIGHT = 'Height';
const ISOSPEEDRATINGS = 'ISOSpeedRatings';
const JOBTITLE = 'jobtitle';
const KEYWORDS = 'keywords';
const MIMETYPE = 'MimeType';
const MODEL = 'Model';
const ORIENTATION = 'Orientation';
const SOFTWARE = 'Software';
const SOURCE = 'source';
const TITLE = 'title';
const WIDTH = 'Width';
const XRESOLUTION = 'XResolution';
const YRESOLUTION = 'YResolution';
const GPSLATITUDE = 'GPSLatitude';
const GPSLONGITUDE = 'GPSLongitude';
const SECTION_FILE = 'FILE';
const SECTION_COMPUTED = 'COMPUTED';
const SECTION_IFD0 = 'IFD0';
const SECTION_THUMBNAIL = 'THUMBNAIL';
const SECTION_COMMENT = 'COMMENT';
const SECTION_EXIF = 'EXIF';
const SECTION_ALL = 'ANY_TAG';
const SECTION_IPTC = 'IPTC';
/**
* A list of section names
*
* @var array
*/
protected $sections = array(
self::SECTION_FILE,
self::SECTION_COMPUTED,
self::SECTION_IFD0,
self::SECTION_THUMBNAIL,
self::SECTION_COMMENT,
self::SECTION_EXIF,
self::SECTION_ALL,
self::SECTION_IPTC,
);
/**
* Maps the ExifTool fields to the fields of
* the \PHPExif\Exif class
*
* @var array
*/
protected $map = array(
self::APERTUREFNUMBER => Exif::APERTURE,
self::FOCUSDISTANCE => Exif::FOCAL_DISTANCE,
self::HEIGHT => Exif::HEIGHT,
self::WIDTH => Exif::WIDTH,
self::CAPTION => Exif::CAPTION,
self::COPYRIGHT => Exif::COPYRIGHT,
self::CREDIT => Exif::CREDIT,
self::HEADLINE => Exif::HEADLINE,
self::JOBTITLE => Exif::JOB_TITLE,
self::KEYWORDS => Exif::KEYWORDS,
self::SOURCE => Exif::SOURCE,
self::TITLE => Exif::TITLE,
self::ARTIST => Exif::AUTHOR,
self::MODEL => Exif::CAMERA,
self::COLORSPACE => Exif::COLORSPACE,
self::DATETIMEORIGINAL => Exif::CREATION_DATE,
self::EXPOSURETIME => Exif::EXPOSURE,
self::FILESIZE => Exif::FILESIZE,
self::FOCALLENGTH => Exif::FOCAL_LENGTH,
self::ISOSPEEDRATINGS => Exif::ISO,
self::MIMETYPE => Exif::MIMETYPE,
self::ORIENTATION => Exif::ORIENTATION,
self::SOFTWARE => Exif::SOFTWARE,
self::XRESOLUTION => Exif::HORIZONTAL_RESOLUTION,
self::YRESOLUTION => Exif::VERTICAL_RESOLUTION,
self::GPSLATITUDE => Exif::GPS,
self::GPSLONGITUDE => Exif::GPS,
);
/**
* 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 ($this->isSection($field) && is_array($value)) {
$subData = $this->mapRawData($value);
$mappedData = array_merge($mappedData, $subData);
continue;
}
if (!$this->isFieldKnown($field)) {
// silently ignore unknown fields
continue;
}
$key = $this->map[$field];
// manipulate the value if necessary
switch ($field) {
case self::DATETIMEORIGINAL:
try {
$value = new DateTime($value);
} catch (Exception $exception) {
continue 2;
}
break;
case self::EXPOSURETIME:
if (!is_float($value)) {
$value = $this->normalizeComponent($value);
}
// 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:
$parts = explode('/', $value);
// Avoid division by zero if focal length is invalid
if (end($parts) == '0') {
$value = 0;
} else {
$value = (int) reset($parts) / (int) end($parts);
}
break;
case self::XRESOLUTION:
case self::YRESOLUTION:
$resolutionParts = explode('/', $value);
$value = (int) reset($resolutionParts);
break;
case self::GPSLATITUDE:
$gpsData['lat'] = $this->extractGPSCoordinate($value);
break;
case self::GPSLONGITUDE:
$gpsData['lon'] = $this->extractGPSCoordinate($value);
break;
}
// set end result
$mappedData[$key] = $value;
}
// add GPS coordinates, if available
if (count($gpsData) === 2) {
$latitudeRef = empty($data['GPSLatitudeRef'][0]) ? 'N' : $data['GPSLatitudeRef'][0];
$longitudeRef = empty($data['GPSLongitudeRef'][0]) ? 'E' : $data['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;
}
/**
* Determines if given field is a section
*
* @param string $field
* @return bool
*/
protected function isSection($field)
{
return (in_array($field, $this->sections));
}
/**
* Determines if the given field is known,
* in a case insensitive way for its first letter.
* Also update $field to keep it valid against the known fields.
*
* @param string &$field
* @return bool
*/
protected function isFieldKnown(&$field)
{
$lcfField = lcfirst($field);
if (array_key_exists($lcfField, $this->map)) {
$field = $lcfField;
return true;
}
$ucfField = ucfirst($field);
if (array_key_exists($ucfField, $this->map)) {
$field = $ucfField;
return true;
}
return false;
}
/**
* Extract GPS coordinates from components array
*
* @param array|string $components
* @return float
*/
protected function extractGPSCoordinate($components)
{
if (!is_array($components)) {
$components = array($components);
}
$components = array_map(array($this, 'normalizeComponent'), $components);
if (count($components) > 2) {
return floatval($components[0]) + (floatval($components[1]) / 60) + (floatval($components[2]) / 3600);
}
return reset($components);
}
/**
* Normalize component
*
* @param mixed $component
* @return int|float
*/
protected function normalizeComponent($component)
{
$parts = explode('/', $component);
if (count($parts) > 1) {
if ($parts[1]) {
return intval($parts[0]) / intval($parts[1]);
}
return 0;
}
return floatval(reset($parts));
}
}