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,132 @@
<?php
/**
* PHP Exif Reader Adapter Abstract: Common functionality for adapters
*
* @link http://github.com/miljar/PHPExif for the canonical source repository
* @copyright Copyright (c) 2013 Tom Van Herreweghe <tom@theanalogguy.be>
* @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License
* @category PHPExif
* @package Reader
*/
namespace PHPExif\Adapter;
use PHPExif\Mapper\MapperInterface;
use PHPExif\Hydrator\HydratorInterface;
/**
* PHP Exif Reader Adapter Abstract
*
* Implements common functionality for the reader adapters
*
* @category PHPExif
* @package Reader
*/
abstract class AdapterAbstract implements AdapterInterface
{
/**
* @var string
*/
protected $hydratorClass = '\\PHPExif\\Hydrator\\Mutator';
/**
* @var \PHPExif\Mapper\MapperInterface
*/
protected $mapper;
/**
* @var \PHPExif\Hydrator\HydratorInterface
*/
protected $hydrator;
/**
* @var string
*/
protected $mapperClass = '';
/**
* Class constructor
*
* @param array $options Optional array of data to initialize the object with
*/
public function __construct(array $options = array())
{
if (!empty($options)) {
$this->setOptions($options);
}
}
/**
* Mutator for the data mapper
*
* @param \PHPExif\Mapper\MapperInterface $mapper
* @return \PHPExif\Adapter\AdapterInterface
*/
public function setMapper(MapperInterface $mapper)
{
$this->mapper = $mapper;
return $this;
}
/**
* Accessor for the data mapper
*
* @return \PHPExif\Mapper\MapperInterface
*/
public function getMapper()
{
if (null === $this->mapper) {
// lazy load one
$mapper = new $this->mapperClass;
$this->setMapper($mapper);
}
return $this->mapper;
}
/**
* Mutator for the hydrator
*
* @param \PHPExif\Hydrator\HydratorInterface $hydrator
* @return \PHPExif\Adapter\AdapterInterface
*/
public function setHydrator(HydratorInterface $hydrator)
{
$this->hydrator = $hydrator;
return $this;
}
/**
* Accessor for the data hydrator
*
* @return \PHPExif\Hydrator\HydratorInterface
*/
public function getHydrator()
{
if (null === $this->hydrator) {
// lazy load one
$hydrator = new $this->hydratorClass;
$this->setHydrator($hydrator);
}
return $this->hydrator;
}
/**
* Set array of options in the current object
*
* @param array $options
* @return \PHPExif\Reader\AdapterAbstract
*/
public function setOptions(array $options)
{
$hydrator = $this->getHydrator();
$hydrator->hydrate($this, $options);
return $this;
}
}

View File

@ -0,0 +1,33 @@
<?php
/**
* PHP Exif Reader Adapter Interface: Defines the interface for reader adapters
*
* @link http://github.com/miljar/PHPExif for the canonical source repository
* @copyright Copyright (c) 2013 Tom Van Herreweghe <tom@theanalogguy.be>
* @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License
* @category PHPExif
* @package Reader
* @codeCoverageIgnore
*/
namespace PHPExif\Adapter;
/**
* PHP Exif Reader Adapter
*
* Defines the interface for reader adapters
*
* @category PHPExif
* @package Reader
*/
interface AdapterInterface
{
/**
* Reads & parses the EXIF data from given file
*
* @param string $file
* @return \PHPExif\Exif Instance of Exif object with data
* @throws \RuntimeException If the EXIF data could not be read
*/
public function getExifFromFile($file);
}

View File

@ -0,0 +1,202 @@
<?php
/**
* PHP Exif Exiftool Reader Adapter
*
* @link http://github.com/miljar/PHPExif for the canonical source repository
* @copyright Copyright (c) 2013 Tom Van Herreweghe <tom@theanalogguy.be>
* @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License
* @category PHPExif
* @package Reader
*/
namespace PHPExif\Adapter;
use PHPExif\Exif;
use InvalidArgumentException;
use RuntimeException;
/**
* PHP Exif Exiftool Reader Adapter
*
* Uses native PHP functionality to read data from a file
*
* @category PHPExif
* @package Reader
*/
class Exiftool extends AdapterAbstract
{
const TOOL_NAME = 'exiftool';
/**
* Path to the exiftool binary
*
* @var string
*/
protected $toolPath;
/**
* @var boolean
*/
protected $numeric = true;
/**
* @var array
*/
protected $encoding = array();
/**
* @var string
*/
protected $mapperClass = '\\PHPExif\\Mapper\\Exiftool';
/**
* Setter for the exiftool binary path
*
* @param string $path The path to the exiftool binary
* @return \PHPExif\Adapter\Exiftool Current instance
* @throws \InvalidArgumentException When path is invalid
*/
public function setToolPath($path)
{
if (!file_exists($path)) {
throw new InvalidArgumentException(
sprintf(
'Given path (%1$s) to the exiftool binary is invalid',
$path
)
);
}
$this->toolPath = $path;
return $this;
}
/**
* @param boolean $numeric
*/
public function setNumeric($numeric)
{
$this->numeric = $numeric;
}
/**
* @see http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html#Q10
* @param array $encoding encoding parameters in an array eg. ["exif" => "UTF-8"]
*/
public function setEncoding($encoding)
{
$possible_keys = array("exif", "iptc", "id3", "photoshop", "quicktime",);
$possible_values = array("UTF8", "cp65001", "UTF-8", "Thai", "cp874", "Latin", "cp1252",
"Latin1", "MacRoman", "cp10000", "Mac", "Roman", "Latin2", "cp1250", "MacLatin2",
"cp10029", "Cyrillic", "cp1251", "Russian", "MacCyrillic", "cp10007", "Greek",
"cp1253", "MacGreek", "cp10006", "Turkish", "cp1254", "MacTurkish", "cp10081",
"Hebrew", "cp1255", "MacRomanian", "cp10010", "Arabic", "cp1256", "MacIceland",
"cp10079", "Baltic", "cp1257", "MacCroatian", "cp10082", "Vietnam", "cp1258",);
foreach ($encoding as $type => $encoding) {
if (in_array($type, $possible_keys) && in_array($encoding, $possible_values)) {
$this->encoding[$type] = $encoding;
}
}
}
/**
* Getter for the exiftool binary path
* Lazy loads the "default" path
*
* @return string
*/
public function getToolPath()
{
if (empty($this->toolPath)) {
$path = exec('which ' . self::TOOL_NAME);
$this->setToolPath($path);
}
return $this->toolPath;
}
/**
* Reads & parses the EXIF data from given file
*
* @param string $file
* @return \PHPExif\Exif Instance of Exif object with data
* @throws \RuntimeException If the EXIF data could not be read
*/
public function getExifFromFile($file)
{
$encoding = '';
if (!empty($this->encoding)) {
$encoding = '-charset ';
foreach ($this->encoding as $key => $value) {
$encoding .= escapeshellarg($key).'='.escapeshellarg($value);
}
}
$result = $this->getCliOutput(
sprintf(
'%1$s%3$s -j -a -G1 %5$s -c %4$s %2$s',
$this->getToolPath(),
escapeshellarg($file),
$this->numeric ? ' -n' : '',
escapeshellarg('%d deg %d\' %.4f"'),
$encoding
)
);
if (!mb_check_encoding($result, "utf-8")) {
$result = utf8_encode($result);
}
$data = json_decode($result, true);
if (!is_array($data)) {
throw new RuntimeException(
'Could not decode exiftool output'
);
}
// map the data:
$mapper = $this->getMapper();
$mapper->setNumeric($this->numeric);
$mappedData = $mapper->mapRawData(reset($data));
// hydrate a new Exif object
$exif = new Exif();
$hydrator = $this->getHydrator();
$hydrator->hydrate($exif, $mappedData);
$exif->setRawData(reset($data));
return $exif;
}
/**
* Returns the output from given cli command
*
* @param string $command
* @return mixed
* @throws RuntimeException If the command can't be executed
*/
protected function getCliOutput($command)
{
$descriptorspec = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'a')
);
$process = proc_open($command, $descriptorspec, $pipes);
if (!is_resource($process)) {
throw new RuntimeException(
'Could not open a resource to the exiftool binary'
);
}
$result = stream_get_contents($pipes[1]);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
return $result;
}
}

View File

@ -0,0 +1,235 @@
<?php
/**
* PHP Exif Native Reader Adapter
*
* @link http://github.com/miljar/PHPExif for the canonical source repository
* @copyright Copyright (c) 2013 Tom Van Herreweghe <tom@theanalogguy.be>
* @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License
* @category PHPExif
* @package Reader
*/
namespace PHPExif\Adapter;
use PHPExif\Exif;
/**
* PHP Exif Native Reader Adapter
*
* Uses native PHP functionality to read data from a file
*
* @category PHPExif
* @package Reader
*/
class Native extends AdapterAbstract
{
const INCLUDE_THUMBNAIL = true;
const NO_THUMBNAIL = false;
const SECTIONS_AS_ARRAYS = true;
const SECTIONS_FLAT = false;
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';
/**
* List of EXIF sections
*
* @var array
*/
protected $requiredSections = array();
/**
* Include the thumbnail in the EXIF data?
*
* @var boolean
*/
protected $includeThumbnail = self::NO_THUMBNAIL;
/**
* Parse the sections as arrays?
*
* @var boolean
*/
protected $sectionsAsArrays = self::SECTIONS_FLAT;
/**
* @var string
*/
protected $mapperClass = '\\PHPExif\\Mapper\\Native';
/**
* Contains the mapping of names to IPTC field numbers
*
* @var array
*/
protected $iptcMapping = array(
'title' => '2#005',
'keywords' => '2#025',
'copyright' => '2#116',
'caption' => '2#120',
'headline' => '2#105',
'credit' => '2#110',
'source' => '2#115',
'jobtitle' => '2#085'
);
/**
* Getter for the EXIF sections
*
* @return array
*/
public function getRequiredSections()
{
return $this->requiredSections;
}
/**
* Setter for the EXIF sections
*
* @param array $sections List of EXIF sections
* @return \PHPExif\Adapter\Native Current instance for chaining
*/
public function setRequiredSections(array $sections)
{
$this->requiredSections = $sections;
return $this;
}
/**
* Adds an EXIF section to the list
*
* @param string $section
* @return \PHPExif\Adapter\Native Current instance for chaining
*/
public function addRequiredSection($section)
{
if (!in_array($section, $this->requiredSections)) {
array_push($this->requiredSections, $section);
}
return $this;
}
/**
* Define if the thumbnail should be included into the EXIF data or not
*
* @param boolean $value
* @return \PHPExif\Adapter\Native Current instance for chaining
*/
public function setIncludeThumbnail($value)
{
$this->includeThumbnail = $value;
return $this;
}
/**
* Returns if the thumbnail should be included into the EXIF data or not
*
* @return boolean
*/
public function getIncludeThumbnail()
{
return $this->includeThumbnail;
}
/**
* Define if the sections should be parsed as arrays
*
* @param boolean $value
* @return \PHPExif\Adapter\Native Current instance for chaining
*/
public function setSectionsAsArrays($value)
{
$this->sectionsAsArrays = (bool) $value;
return $this;
}
/**
* Returns if the sections should be parsed as arrays
*
* @return boolean
*/
public function getSectionsAsArrays()
{
return $this->sectionsAsArrays;
}
/**
* Reads & parses the EXIF data from given file
*
* @param string $file
* @return \PHPExif\Exif|boolean Instance of Exif object with data
*/
public function getExifFromFile($file)
{
$sections = $this->getRequiredSections();
$sections = implode(',', $sections);
$sections = (empty($sections)) ? null : $sections;
$data = @exif_read_data(
$file,
$sections,
$this->getSectionsAsArrays(),
$this->getIncludeThumbnail()
);
if (false === $data) {
return false;
}
$xmpData = $this->getIptcData($file);
$data = array_merge($data, array(self::SECTION_IPTC => $xmpData));
// map the data:
$mapper = $this->getMapper();
$mappedData = $mapper->mapRawData($data);
// hydrate a new Exif object
$exif = new Exif();
$hydrator = $this->getHydrator();
$hydrator->hydrate($exif, $mappedData);
$exif->setRawData($data);
return $exif;
}
/**
* Returns an array of IPTC data
*
* @param string $file The file to read the IPTC data from
* @return array
*/
public function getIptcData($file)
{
getimagesize($file, $info);
$arrData = array();
if (isset($info['APP13'])) {
$iptc = iptcparse($info['APP13']);
foreach ($this->iptcMapping as $name => $field) {
if (!isset($iptc[$field])) {
continue;
}
if (count($iptc[$field]) === 1) {
$arrData[$name] = reset($iptc[$field]);
} else {
$arrData[$name] = $iptc[$field];
}
}
}
return $arrData;
}
}

View File

@ -0,0 +1,28 @@
<?php
/**
* PHP Exif Reader Adapter Interface: Defines the interface for reader adapters
*
* @link http://github.com/miljar/PHPExif for the canonical source repository
* @copyright Copyright (c) 2013 Tom Van Herreweghe <tom@theanalogguy.be>
* @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License
* @category PHPExif
* @package Reader
* @codeCoverageIgnore
*/
namespace PHPExif\Adapter;
use Exception;
/**
* PHP Exif Reader Adapter
*
* Defines the interface for reader adapters
*
* @category PHPExif
* @package Reader
*/
class NoAdapterException extends Exception
{
//empty
}

843
vendor/miljar/php-exif/lib/PHPExif/Exif.php vendored Executable file
View File

@ -0,0 +1,843 @@
<?php
/**
* PHP Exif Reader: Reads EXIF metadata from a file, without having to install additional PHP modules
*
* @link http://github.com/miljar/PHPExif for the canonical source repository
* @copyright Copyright (c) 2013 Tom Van Herreweghe <tom@theanalogguy.be>
* @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License
* @category PHPExif
* @package Exif
*/
namespace PHPExif;
/**
* PHP Exif Reader
*
* Responsible for all the read operations on a file's EXIF metadata
*
* @category PHPExif
* @package Exif
* @
*/
class Exif
{
const APERTURE = 'aperture';
const AUTHOR = 'author';
const CAMERA = 'camera';
const CAPTION = 'caption';
const COLORSPACE = 'ColorSpace';
const COPYRIGHT = 'copyright';
const CREATION_DATE = 'creationdate';
const CREDIT = 'credit';
const EXPOSURE = 'exposure';
const FILESIZE = 'FileSize';
const FOCAL_LENGTH = 'focalLength';
const FOCAL_DISTANCE = 'focalDistance';
const HEADLINE = 'headline';
const HEIGHT = 'height';
const HORIZONTAL_RESOLUTION = 'horizontalResolution';
const ISO = 'iso';
const JOB_TITLE = 'jobTitle';
const KEYWORDS = 'keywords';
const MIMETYPE = 'MimeType';
const ORIENTATION = 'Orientation';
const SOFTWARE = 'software';
const SOURCE = 'source';
const TITLE = 'title';
const VERTICAL_RESOLUTION = 'verticalResolution';
const WIDTH = 'width';
const GPS = 'gps';
/**
* The mapped EXIF data
*
* @var array
*/
protected $data = array();
/**
* The raw EXIF data
*
* @var array
*/
protected $rawData = array();
/**
* Class constructor
*
* @param array $data
*/
public function __construct(array $data = array())
{
$this->setData($data);
}
/**
* Sets the raw EXIF data
*
* @param array $data The data to set
* @return \PHPExif\Exif Current instance for chaining
*/
public function setRawData(array $data)
{
$this->rawData = $data;
return $this;
}
/**
* Returns all EXIF data in the raw original format
*
* @return array
*/
public function getRawData()
{
return $this->rawData;
}
/**
* Sets the mapped EXIF data
*
* @param array $data The data to set
* @return \PHPExif\Exif Current instance for chaining
*/
public function setData(array $data)
{
$this->data = $data;
return $this;
}
/**
* Returns the mapped EXIF data
*
* @return array
*/
public function getData()
{
return $this->data;
}
/**
* Returns the Aperture F-number
*
* @return string|boolean
*/
public function getAperture()
{
if (!isset($this->data[self::APERTURE])) {
return false;
}
return $this->data[self::APERTURE];
}
/**
* Sets the Aperture F-number
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setAperture($value)
{
$this->data[self::APERTURE] = $value;
return $this;
}
/**
* Returns the Author
*
* @return string|boolean
*/
public function getAuthor()
{
if (!isset($this->data[self::AUTHOR])) {
return false;
}
return $this->data[self::AUTHOR];
}
/**
* Sets the Author
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setAuthor($value)
{
$this->data[self::AUTHOR] = $value;
return $this;
}
/**
* Returns the Headline
*
* @return string|boolean
*/
public function getHeadline()
{
if (!isset($this->data[self::HEADLINE])) {
return false;
}
return $this->data[self::HEADLINE];
}
/**
* Sets the Headline
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setHeadline($value)
{
$this->data[self::HEADLINE] = $value;
return $this;
}
/**
* Returns the Credit
*
* @return string|boolean
*/
public function getCredit()
{
if (!isset($this->data[self::CREDIT])) {
return false;
}
return $this->data[self::CREDIT];
}
/**
* Sets the Credit
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setCredit($value)
{
$this->data[self::CREDIT] = $value;
return $this;
}
/**
* Returns the source
*
* @return string|boolean
*/
public function getSource()
{
if (!isset($this->data[self::SOURCE])) {
return false;
}
return $this->data[self::SOURCE];
}
/**
* Sets the Source
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setSource($value)
{
$this->data[self::SOURCE] = $value;
return $this;
}
/**
* Returns the Jobtitle
*
* @return string|boolean
*/
public function getJobtitle()
{
if (!isset($this->data[self::JOB_TITLE])) {
return false;
}
return $this->data[self::JOB_TITLE];
}
/**
* Sets the Jobtitle
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setJobtitle($value)
{
$this->data[self::JOB_TITLE] = $value;
return $this;
}
/**
* Returns the ISO speed
*
* @return int|boolean
*/
public function getIso()
{
if (!isset($this->data[self::ISO])) {
return false;
}
return $this->data[self::ISO];
}
/**
* Sets the ISO
*
* @param int $value
* @return \PHPExif\Exif
*/
public function setIso($value)
{
$this->data[self::ISO] = $value;
return $this;
}
/**
* Returns the Exposure
*
* @return string|boolean
*/
public function getExposure()
{
if (!isset($this->data[self::EXPOSURE])) {
return false;
}
return $this->data[self::EXPOSURE];
}
/**
* Sets the Exposure
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setExposure($value)
{
$this->data[self::EXPOSURE] = $value;
return $this;
}
/**
* Returns the Exposure
*
* @return float|boolean
*/
public function getExposureMilliseconds()
{
if (!isset($this->data[self::EXPOSURE])) {
return false;
}
if (is_numeric($this->data[self::EXPOSURE])) {
return $this->data[self::EXPOSURE] + 0;
}
$exposureParts = explode('/', $this->data[self::EXPOSURE]);
return (int) reset($exposureParts) / (int) end($exposureParts);
}
/**
* Returns the focus distance, if it exists
*
* @return string|boolean
*/
public function getFocusDistance()
{
if (!isset($this->data[self::FOCAL_DISTANCE])) {
return false;
}
return $this->data[self::FOCAL_DISTANCE];
}
/**
* Sets the focus distance
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setFocusDistance($value)
{
$this->data[self::FOCAL_DISTANCE] = $value;
return $this;
}
/**
* Returns the width in pixels, if it exists
*
* @return int|boolean
*/
public function getWidth()
{
if (!isset($this->data[self::WIDTH])) {
return false;
}
return $this->data[self::WIDTH];
}
/**
* Sets the width
*
* @param int $value
* @return \PHPExif\Exif
*/
public function setWidth($value)
{
$this->data[self::WIDTH] = $value;
return $this;
}
/**
* Returns the height in pixels, if it exists
*
* @return int|boolean
*/
public function getHeight()
{
if (!isset($this->data[self::HEIGHT])) {
return false;
}
return $this->data[self::HEIGHT];
}
/**
* Sets the height
*
* @param int $value
* @return \PHPExif\Exif
*/
public function setHeight($value)
{
$this->data[self::HEIGHT] = $value;
return $this;
}
/**
* Returns the title, if it exists
*
* @return string|boolean
*/
public function getTitle()
{
if (!isset($this->data[self::TITLE])) {
return false;
}
return $this->data[self::TITLE];
}
/**
* Sets the title
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setTitle($value)
{
$this->data[self::TITLE] = $value;
return $this;
}
/**
* Returns the caption, if it exists
*
* @return string|boolean
*/
public function getCaption()
{
if (!isset($this->data[self::CAPTION])) {
return false;
}
return $this->data[self::CAPTION];
}
/**
* Sets the caption
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setCaption($value)
{
$this->data[self::CAPTION] = $value;
return $this;
}
/**
* Returns the copyright, if it exists
*
* @return string|boolean
*/
public function getCopyright()
{
if (!isset($this->data[self::COPYRIGHT])) {
return false;
}
return $this->data[self::COPYRIGHT];
}
/**
* Sets the copyright
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setCopyright($value)
{
$this->data[self::COPYRIGHT] = $value;
return $this;
}
/**
* Returns the keywords, if they exists
*
* @return array|boolean
*/
public function getKeywords()
{
if (!isset($this->data[self::KEYWORDS])) {
return false;
}
return $this->data[self::KEYWORDS];
}
/**
* Sets the keywords
*
* @param array $value
* @return \PHPExif\Exif
*/
public function setKeywords($value)
{
$this->data[self::KEYWORDS] = $value;
return $this;
}
/**
* Returns the camera, if it exists
*
* @return string|boolean
*/
public function getCamera()
{
if (!isset($this->data[self::CAMERA])) {
return false;
}
return $this->data[self::CAMERA];
}
/**
* Sets the camera
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setCamera($value)
{
$this->data[self::CAMERA] = $value;
return $this;
}
/**
* Returns the horizontal resolution in DPI, if it exists
*
* @return int|boolean
*/
public function getHorizontalResolution()
{
if (!isset($this->data[self::HORIZONTAL_RESOLUTION])) {
return false;
}
return $this->data[self::HORIZONTAL_RESOLUTION];
}
/**
* Sets the horizontal resolution in DPI
*
* @param int $value
* @return \PHPExif\Exif
*/
public function setHorizontalResolution($value)
{
$this->data[self::HORIZONTAL_RESOLUTION] = $value;
return $this;
}
/**
* Returns the vertical resolution in DPI, if it exists
*
* @return int|boolean
*/
public function getVerticalResolution()
{
if (!isset($this->data[self::VERTICAL_RESOLUTION])) {
return false;
}
return $this->data[self::VERTICAL_RESOLUTION];
}
/**
* Sets the vertical resolution in DPI
*
* @param int $value
* @return \PHPExif\Exif
*/
public function setVerticalResolution($value)
{
$this->data[self::VERTICAL_RESOLUTION] = $value;
return $this;
}
/**
* Returns the software, if it exists
*
* @return string|boolean
*/
public function getSoftware()
{
if (!isset($this->data[self::SOFTWARE])) {
return false;
}
return $this->data[self::SOFTWARE];
}
/**
* Sets the software
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setSoftware($value)
{
$this->data[self::SOFTWARE] = trim($value);
return $this;
}
/**
* Returns the focal length in mm, if it exists
*
* @return float|boolean
*/
public function getFocalLength()
{
if (!isset($this->data[self::FOCAL_LENGTH])) {
return false;
}
return $this->data[self::FOCAL_LENGTH];
}
/**
* Sets the focal length in mm
*
* @param float $value
* @return \PHPExif\Exif
*/
public function setFocalLength($value)
{
$this->data[self::FOCAL_LENGTH] = $value;
return $this;
}
/**
* Returns the creation datetime, if it exists
*
* @return \DateTime|boolean
*/
public function getCreationDate()
{
if (!isset($this->data[self::CREATION_DATE])) {
return false;
}
return $this->data[self::CREATION_DATE];
}
/**
* Sets the creation datetime
*
* @param \DateTime $value
* @return \PHPExif\Exif
*/
public function setCreationDate(\DateTime $value)
{
$this->data[self::CREATION_DATE] = $value;
return $this;
}
/**
* Returns the colorspace, if it exists
*
* @return string|boolean
*/
public function getColorSpace()
{
if (!isset($this->data[self::COLORSPACE])) {
return false;
}
return $this->data[self::COLORSPACE];
}
/**
* Sets the colorspace
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setColorSpace($value)
{
$this->data[self::COLORSPACE] = $value;
return $this;
}
/**
* Returns the mimetype, if it exists
*
* @return string|boolean
*/
public function getMimeType()
{
if (!isset($this->data[self::MIMETYPE])) {
return false;
}
return $this->data[self::MIMETYPE];
}
/**
* Sets the mimetype
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setMimeType($value)
{
$this->data[self::MIMETYPE] = $value;
return $this;
}
/**
* Returns the filesize, if it exists
*
* @return int|boolean
*/
public function getFileSize()
{
if (!isset($this->data[self::FILESIZE])) {
return false;
}
return $this->data[self::FILESIZE];
}
/**
* Sets the filesize
*
* @param int $value
* @return \PHPExif\Exif
*/
public function setFileSize($value)
{
$this->data[self::FILESIZE] = $value;
return $this;
}
/**
* Returns the orientation, if it exists
*
* @return int|boolean
*/
public function getOrientation()
{
if (!isset($this->data[self::ORIENTATION])) {
return false;
}
return $this->data[self::ORIENTATION];
}
/**
* Sets the orientation
*
* @param int $value
* @return \PHPExif\Exif
*/
public function setOrientation($value)
{
$this->data[self::ORIENTATION] = $value;
return $this;
}
/**
* Returns GPS coordinates, if it exists
*
* @return array|boolean
*/
public function getGPS()
{
if (!isset($this->data[self::GPS])) {
return false;
}
return $this->data[self::GPS];
}
/**
* Sets the GPS coordinates
*
* @param string $value
* @return \PHPExif\Exif
*/
public function setGPS($value)
{
$this->data[self::GPS] = $value;
return $this;
}
}

View File

@ -0,0 +1,33 @@
<?php
/**
* PHP Exif Hydrator Interface: Defines the interface for a hydrator
*
* @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 Hydrator
* @codeCoverageIgnore
*/
namespace PHPExif\Hydrator;
/**
* PHP Exif Hydrator
*
* Defines the interface for a hydrator
*
* @category PHPExif
* @package Hydrator
*/
interface HydratorInterface
{
/**
* Hydrates given array of data into the given Exif object
*
* @param object $object
* @param array $data
* @return void
*/
public function hydrate($object, array $data);
}

View File

@ -0,0 +1,56 @@
<?php
/**
* PHP Exif Mutator Hydrator: Hydrate an object
* by manipulating the object with its mutator methods
*
* @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 Hydrator
*/
namespace PHPExif\Hydrator;
/**
* PHP Exif Mutator Hydrator
*
* Hydrates an object by setting data with
* the class mutator methods
*
* @category PHPExif
* @package Hydrator
*/
class Mutator implements HydratorInterface
{
/**
* Hydrates given array of data into the given Exif object
*
* @param object $object
* @param array $data
* @return void
*/
public function hydrate($object, array $data)
{
foreach ($data as $property => $value) {
$mutator = $this->determineMutator($property);
if (method_exists($object, $mutator)) {
$object->$mutator($value);
}
}
}
/**
* Determines the name of the mutator method for given property name
*
* @param string $property The property to determine the mutator for
* @return string The name of the mutator method
*/
protected function determineMutator($property)
{
$method = 'set' . ucfirst($property);
return $method;
}
}

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));
}
}

View File

@ -0,0 +1,111 @@
<?php
/**
* PHP Exif Reader: Reads EXIF metadata from a file
*
* @link http://github.com/miljar/PHPExif for the canonical source repository
* @copyright Copyright (c) 2013 Tom Van Herreweghe <tom@theanalogguy.be>
* @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License
* @category PHPExif
* @package Reader
*/
namespace PHPExif\Reader;
use PHPExif\Adapter\AdapterInterface;
use PHPExif\Adapter\NoAdapterException;
use PHPExif\Adapter\Exiftool as ExiftoolAdapter;
use PHPExif\Adapter\Native as NativeAdapter;
/**
* PHP Exif Reader
*
* Responsible for all the read operations on a file's EXIF metadata
*
* @category PHPExif
* @package Reader
* @
*/
class Reader implements ReaderInterface
{
const TYPE_NATIVE = 'native';
const TYPE_EXIFTOOL = 'exiftool';
/**
* The current adapter
*
* @var \PHPExif\Adapter\AdapterInterface
*/
protected $adapter;
/**
* Reader constructor
*
* @param \PHPExif\Adapter\AdapterInterface $adapter
*/
public function __construct(AdapterInterface $adapter)
{
$this->adapter = $adapter;
}
/**
* Getter for the reader adapter
*
* @return \PHPExif\Adapter\AdapterInterface
* @throws NoAdapterException When no adapter is set
*/
public function getAdapter()
{
if (empty($this->adapter)) {
throw new NoAdapterException('No adapter set in the reader');
}
return $this->adapter;
}
/**
* Factory for the reader
*
* @param string $type
* @return $this
* @throws \InvalidArgumentException When given type is invalid
*/
public static function factory($type)
{
$classname = get_called_class();
switch ($type) {
case self::TYPE_NATIVE:
$adapter = new NativeAdapter();
break;
case self::TYPE_EXIFTOOL:
$adapter = new ExiftoolAdapter();
break;
default:
throw new \InvalidArgumentException(
sprintf('Unknown type "%1$s"', $type)
);
}
return new $classname($adapter);
}
/**
* Reads & parses the EXIF data from given file
*
* @param string $file
* @return \PHPExif\Exif Instance of Exif object with data
*/
public function read($file)
{
return $this->getAdapter()->getExifFromFile($file);
}
/**
* alias to read method
*
* @param string $file
* @return \PHPExif\Exif Instance of Exif object with data
*/
public function getExifFromFile($file)
{
return $this->read($file);
}
}

View File

@ -0,0 +1,33 @@
<?php
/**
* PHP Exif Reader Interface: Defines the interface for
* the Reader functionality
*
* @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 Reader
* @codeCoverageIgnore
*/
namespace PHPExif\Reader;
/**
* PHP Exif Reader
*
* Defines the interface for reader functionality
*
* @category PHPExif
* @package Reader
*/
interface ReaderInterface
{
/**
* Reads & parses the EXIF data from given file
*
* @param string $file
* @return \PHPExif\Exif Instance of Exif object with data
*/
public function read($file);
}