Skip to content

Commit a4ba0d1

Browse files
committed
Merge pull request #34 from Miljar/rel/v0.4.0
Rel/v0.4.0
2 parents fe64685 + ff65183 commit a4ba0d1

25 files changed

+1936
-670
lines changed

CHANGELOG.rst

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
CHANGELOG
22
=====
33

4+
0.4.0
5+
-----
6+
7+
* Improvement `#25`_: Extracted mapping logic into separate classes
8+
* Added ``GPS`` information
9+
* Improved unit tests; coverage up to 100%
10+
* Added contributor to README.md
11+
* Added extra stuff about unit tests to the ``Contributing`` section of the README.md
12+
413
0.3.0
514
-----
615

@@ -12,6 +21,7 @@ CHANGELOG
1221
* Composer.json: added semver version for phpmd; removed pdepend
1322
* added ``Orientation``, ``MimeType``, ``FileSize`` and ``ColorSpace`` options to EXIF
1423

24+
.. _`#25`: https://github.com/Miljar/php-exif/issues/25
1525
.. _`#24`: https://github.com/Miljar/php-exif/issues/24
1626
.. _`#18`: https://github.com/Miljar/php-exif/issues/18
1727
.. _`#15`: https://github.com/Miljar/php-exif/issues/15

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# [PHPExif v0.3.0](http://github.com/Miljar/php-exif) [![Build Status](https://travis-ci.org/Miljar/php-exif.png?branch=master)](https://travis-ci.org/Miljar/php-exif) [![Coverage Status](https://coveralls.io/repos/Miljar/php-exif/badge.svg?branch=master)](https://coveralls.io/r/Miljar/php-exif?branch=master) [![Code Climate](https://codeclimate.com/github/Miljar/php-exif/badges/gpa.svg)](https://codeclimate.com/github/Miljar/php-exif)
1+
# [PHPExif v0.4.0](http://github.com/Miljar/php-exif) [![Build Status](https://travis-ci.org/Miljar/php-exif.png?branch=master)](https://travis-ci.org/Miljar/php-exif) [![Coverage Status](https://coveralls.io/repos/Miljar/php-exif/badge.svg?branch=master)](https://coveralls.io/r/Miljar/php-exif?branch=master) [![Code Climate](https://codeclimate.com/github/Miljar/php-exif/badges/gpa.svg)](https://codeclimate.com/github/Miljar/php-exif)
22

33
PHPExif is a library which gives you easy access to the EXIF meta-data of an image.
44

@@ -12,7 +12,7 @@ PHPExif serves as a wrapper around some native or CLI tools which access this EX
1212
## Installation (composer)
1313

1414
```json
15-
"miljar/php-exif": "~0.3.0"
15+
"miljar/php-exif": "~0.4.0"
1616
```
1717

1818

@@ -27,6 +27,7 @@ PHPExif serves as a wrapper around some native or CLI tools which access this EX
2727
Please submit all pull requests against the correct branch. The release branch for the next version is a branch with the same name as the next version. Bugfixes should go in the master branch, unless they are for code in a new release branch.
2828

2929
PHPExif is written according the [PSR-0/1/2 standards](http://www.php-fig.org/). When submitting code, please make sure it is conform these standards.
30+
We aim to have all functionality covered by unit tests. When submitting code, you are strongly encouraged to unit test your code and to keep the level of code coverage on par with the current level.
3031

3132
All contributions are welcomed and greatly appreciated.
3233

@@ -40,6 +41,7 @@ Have a bug or a feature request? [Please open a new issue](https://github.com/Mi
4041
* [Ingewikkeld](https://github.com/Ingewikkeld)
4142
* [Christophe Singer](https://github.com/wasinger)
4243
* [Hanov Ruslan](https://github.com/hanovruslan)
44+
* [Julian Gutierrez](https://github.com/juliangut)
4345

4446
## License
4547

lib/PHPExif/Adapter/AdapterAbstract.php

+59-53
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
namespace PHPExif\Adapter;
1313

14+
use PHPExif\Mapper\MapperInterface;
15+
use PHPExif\Hydrator\HydratorInterface;
16+
1417
/**
1518
* PHP Exif Reader Adapter Abstract
1619
*
@@ -21,10 +24,25 @@
2124
*/
2225
abstract class AdapterAbstract implements AdapterInterface
2326
{
27+
/**
28+
* @var string
29+
*/
30+
protected $hydratorClass = '\\PHPExif\\Hydrator\\Mutator';
31+
32+
/**
33+
* @var \PHPExif\Mapper\MapperInterface
34+
*/
35+
protected $mapper;
36+
37+
/**
38+
* @var \PHPExif\Hydrator\HydratorInterface
39+
*/
40+
protected $hydrator;
41+
2442
/**
2543
* Class constructor
2644
*
27-
* @param array $data Optional array of data to initialize the object with
45+
* @param array $options Optional array of data to initialize the object with
2846
*/
2947
public function __construct(array $options = array())
3048
{
@@ -34,88 +52,76 @@ public function __construct(array $options = array())
3452
}
3553

3654
/**
37-
* Set array of options in the current object
55+
* Mutator for the data mapper
3856
*
39-
* @param array $options
40-
* @return \PHPExif\Reader\AdapterAbstract
57+
* @param \PHPExif\Mapper\MapperInterface $mapper
58+
* @return \PHPExif\Adapter\AdapterInterface
4159
*/
42-
public function setOptions(array $options)
60+
public function setMapper(MapperInterface $mapper)
4361
{
44-
foreach ($options as $property => $value) {
45-
$setter = $this->determinePropertySetter($property);
46-
if (method_exists($this, $setter)) {
47-
$this->$setter($value);
48-
}
49-
}
62+
$this->mapper = $mapper;
5063

5164
return $this;
5265
}
5366

5467
/**
55-
* Detemines the name of the getter method for given property name
68+
* Accessor for the data mapper
5669
*
57-
* @param string $property The property to determine the getter for
58-
* @return string The name of the getter method
70+
* @return \PHPExif\Mapper\MapperInterface
5971
*/
60-
protected function determinePropertyGetter($property)
72+
public function getMapper()
6173
{
62-
$method = 'get' . ucfirst($property);
63-
return $method;
74+
if (null === $this->mapper) {
75+
// lazy load one
76+
$mapper = new $this->mapperClass;
77+
78+
$this->setMapper($mapper);
79+
}
80+
81+
return $this->mapper;
6482
}
6583

6684
/**
67-
* Detemines the name of the setter method for given property name
85+
* Mutator for the hydrator
6886
*
69-
* @param string $property The property to determine the setter for
70-
* @return string The name of the setter method
87+
* @param \PHPExif\Hydrator\HydratorInterface $hydrator
88+
* @return \PHPExif\Adapter\AdapterInterface
7189
*/
72-
protected function determinePropertySetter($property)
90+
public function setHydrator(HydratorInterface $hydrator)
7391
{
74-
$method = 'set' . ucfirst($property);
75-
return $method;
92+
$this->hydrator = $hydrator;
93+
94+
return $this;
7695
}
7796

7897
/**
79-
* Get a list of the class constants prefixed with given $type
98+
* Accessor for the data hydrator
8099
*
81-
* @param string $type
82-
* @return array
100+
* @return \PHPExif\Hydrator\HydratorInterface
83101
*/
84-
public function getClassConstantsOfType($type)
102+
public function getHydrator()
85103
{
86-
$class = new \ReflectionClass(get_called_class());
87-
$constants = $class->getConstants();
88-
89-
$list = array();
90-
$type = strtoupper($type) . '_';
91-
foreach ($constants as $key => $value) {
92-
if (strpos($key, $type) === 0) {
93-
$list[$key] = $value;
94-
}
104+
if (null === $this->hydrator) {
105+
// lazy load one
106+
$hydrator = new $this->hydratorClass;
107+
108+
$this->setHydrator($hydrator);
95109
}
96-
return $list;
110+
111+
return $this->hydrator;
97112
}
98113

99114
/**
100-
* Returns an array notation of current instance
115+
* Set array of options in the current object
101116
*
102-
* @return array
117+
* @param array $options
118+
* @return \PHPExif\Reader\AdapterAbstract
103119
*/
104-
public function toArray()
120+
public function setOptions(array $options)
105121
{
106-
$rc = new \ReflectionClass(get_class($this));
107-
$properties = $rc->getProperties();
108-
$arrResult = array();
109-
110-
foreach ($properties as $rp) {
111-
/* @var $rp \ReflectionProperty */
112-
$getter = $this->determinePropertyGetter($rp->getName());
113-
if (!method_exists($this, $getter)) {
114-
continue;
115-
}
116-
$arrResult[$rp->getName()] = $this->$getter();
117-
}
122+
$hydrator = $this->getHydrator();
123+
$hydrator->hydrate($this, $options);
118124

119-
return $arrResult;
125+
return $this;
120126
}
121127
}

lib/PHPExif/Adapter/AdapterInterface.php

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* @license http://github.com/miljar/PHPExif/blob/master/LICENSE MIT License
88
* @category PHPExif
99
* @package Reader
10+
* @codeCoverageIgnore
1011
*/
1112

1213
namespace PHPExif\Adapter;

lib/PHPExif/Adapter/Exiftool.php

+15-95
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use PHPExif\Exif;
1515
use InvalidArgumentException;
1616
use RuntimeException;
17-
use DateTime;
1817

1918
/**
2019
* PHP Exif Exiftool Reader Adapter
@@ -40,6 +39,11 @@ class Exiftool extends AdapterAbstract
4039
*/
4140
protected $numeric = true;
4241

42+
/**
43+
* @var string
44+
*/
45+
protected $mapperClass = '\\PHPExif\\Mapper\\Exiftool';
46+
4347
/**
4448
* Setter for the exiftool binary path
4549
*
@@ -109,8 +113,16 @@ public function getExifFromFile($file)
109113
);
110114

111115
$data = json_decode($result, true);
112-
$mappedData = $this->mapData(reset($data));
113-
$exif = new Exif($mappedData);
116+
117+
// map the data:
118+
$mapper = $this->getMapper();
119+
$mapper->setNumeric($this->numeric);
120+
$mappedData = $mapper->mapRawData(reset($data));
121+
122+
// hydrate a new Exif object
123+
$exif = new Exif();
124+
$hydrator = $this->getHydrator();
125+
$hydrator->hydrate($exif, $mappedData);
114126
$exif->setRawData(reset($data));
115127

116128
return $exif;
@@ -148,96 +160,4 @@ protected function getCliOutput($command)
148160

149161
return $result;
150162
}
151-
152-
/**
153-
* Maps native data to Exif format
154-
*
155-
* @param array $source
156-
* @return array
157-
*/
158-
public function mapData(array $source)
159-
{
160-
$focalLength = false;
161-
if (isset($source['FocalLength'])) {
162-
$focalLengthParts = explode(' ', $source['FocalLength']);
163-
$focalLength = (int) reset($focalLengthParts);
164-
}
165-
166-
$exposureTime = false;
167-
if (isset($source['ExposureTime'])) {
168-
$exposureTime = '1/' . round(1 / $source['ExposureTime']);
169-
}
170-
171-
$caption = false;
172-
if (isset($source['Caption'])) {
173-
$caption = $source['Caption'];
174-
} elseif (isset($source['Caption-Abstract'])) {
175-
$caption = $source['Caption-Abstract'];
176-
}
177-
178-
$gpsLocation = false;
179-
if (isset($source['GPSLatitudeRef']) && isset($source['GPSLongitudeRef'])) {
180-
$latitude = $this->extractGPSCoordinates($source['GPSLatitude']);
181-
$longitude = $this->extractGPSCoordinates($source['GPSLongitude']);
182-
183-
if ($latitude !== false && $longitude !== false) {
184-
$gpsLocation = sprintf(
185-
'%s,%s',
186-
(strtoupper($source['GPSLatitudeRef'][0]) === 'S' ? -1 : 1) * $latitude,
187-
(strtoupper($source['GPSLongitudeRef'][0]) === 'W' ? -1 : 1) * $longitude
188-
);
189-
}
190-
}
191-
192-
return array(
193-
Exif::APERTURE => (!isset($source['Aperture'])) ?
194-
false : sprintf('f/%01.1f', $source['Aperture']),
195-
Exif::AUTHOR => (!isset($source['Artist'])) ? false : $source['Artist'],
196-
Exif::CAMERA => (!isset($source['Model'])) ? false : $source['Model'],
197-
Exif::CAPTION => $caption,
198-
Exif::COLORSPACE => (!isset($source[Exif::COLORSPACE]) ? false : $source[Exif::COLORSPACE]),
199-
Exif::COPYRIGHT => (!isset($source['Copyright'])) ? false : $source['Copyright'],
200-
Exif::CREATION_DATE => (!isset($source['CreateDate'])) ?
201-
false : DateTime::createFromFormat('Y:m:d H:i:s', $source['CreateDate']),
202-
Exif::CREDIT => (!isset($source['Credit'])) ? false : $source['Credit'],
203-
Exif::EXPOSURE => $exposureTime,
204-
Exif::FILESIZE => (!isset($source[Exif::FILESIZE]) ? false : $source[Exif::FILESIZE]),
205-
Exif::FOCAL_LENGTH => $focalLength,
206-
Exif::FOCAL_DISTANCE => (!isset($source['ApproximateFocusDistance'])) ?
207-
false : sprintf('%1$sm', $source['ApproximateFocusDistance']),
208-
Exif::HEADLINE => (!isset($source['Headline'])) ? false : $source['Headline'],
209-
Exif::HEIGHT => (!isset($source['ImageHeight'])) ? false : $source['ImageHeight'],
210-
Exif::HORIZONTAL_RESOLUTION => (!isset($source['XResolution'])) ? false : $source['XResolution'],
211-
Exif::ISO => (!isset($source['ISO'])) ? false : $source['ISO'],
212-
Exif::JOB_TITLE => (!isset($source['JobTitle'])) ? false : $source['JobTitle'],
213-
Exif::KEYWORDS => (!isset($source['Keywords'])) ? false : $source['Keywords'],
214-
Exif::MIMETYPE => (!isset($source['MIMEType'])) ? false : $source['MIMEType'],
215-
Exif::ORIENTATION => (!isset($source['Orientation'])) ? false : $source['Orientation'],
216-
Exif::SOFTWARE => (!isset($source['Software'])) ? false : $source['Software'],
217-
Exif::SOURCE => (!isset($source['Source'])) ? false : $source['Source'],
218-
Exif::TITLE => (!isset($source['Title'])) ? false : $source['Title'],
219-
Exif::VERTICAL_RESOLUTION => (!isset($source['YResolution'])) ? false : $source['YResolution'],
220-
Exif::WIDTH => (!isset($source['ImageWidth'])) ? false : $source['ImageWidth'],
221-
Exif::GPS => $gpsLocation,
222-
);
223-
}
224-
225-
/**
226-
* Extract GPS coordinates from formatted string
227-
*
228-
* @param string $coordinates
229-
* @return array
230-
*/
231-
protected function extractGPSCoordinates($coordinates)
232-
{
233-
if ($this->numeric === true) {
234-
return abs((float) $coordinates);
235-
} else {
236-
if (!preg_match('!^([0-9.]+) deg ([0-9.]+)\' ([0-9.]+)"!', $coordinates, $matches)) {
237-
return false;
238-
}
239-
240-
return intval($matches[1]) + (intval($matches[2]) / 60) + (floatval($matches[3]) / 3600);
241-
}
242-
}
243163
}

0 commit comments

Comments
 (0)