Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions lib/PHPExif/Adapter/Exiftool.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,15 @@ public function getToolPath()
*/
public function getExifFromFile($file)
{
$gpsFormat = '%d deg %d\' %.4f\"';

$result = $this->getCliOutput(
sprintf(
'%1$s%3$s -j %2$s',
'%1$s%3$s -j -c "%4$s" %2$s',
$this->getToolPath(),
$file,
$this->numeric ? ' -n' : ''
$this->numeric ? ' -n' : '',
$gpsFormat
)
);

Expand Down Expand Up @@ -172,6 +175,20 @@ public function mapData(array $source)
$caption = $source['Caption-Abstract'];
}

$gpsLocation = false;
if (isset($source['GPSLatitudeRef']) && isset($source['GPSLongitudeRef'])) {
$latitude = $this->extractGPSCoordinates($source['GPSLatitude']);
$longitude = $this->extractGPSCoordinates($source['GPSLongitude']);

if ($latitude !== false && $longitude !== false) {
$gpsLocation = sprintf(
'%s,%s',
(strtoupper($source['GPSLatitudeRef'][0]) === 'S' ? -1 : 1) * $latitude,
(strtoupper($source['GPSLongitudeRef'][0]) === 'W' ? -1 : 1) * $longitude
);
}
}

return array(
Exif::APERTURE => (!isset($source['Aperture'])) ?
false : sprintf('f/%01.1f', $source['Aperture']),
Expand Down Expand Up @@ -201,6 +218,26 @@ public function mapData(array $source)
Exif::TITLE => (!isset($source['Title'])) ? false : $source['Title'],
Exif::VERTICAL_RESOLUTION => (!isset($source['YResolution'])) ? false : $source['YResolution'],
Exif::WIDTH => (!isset($source['ImageWidth'])) ? false : $source['ImageWidth'],
Exif::GPS => $gpsLocation,
);
}

/**
* Extract GPS coordinates from formatted string
*
* @param string $coordinates
* @return array
*/
protected function extractGPSCoordinates($coordinates)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you unit test this method? Coverage is brought down now, which I want to avoid.

{
if ($this->numeric === true) {
return abs((float) $coordinates);
} else {
if (!preg_match('!^([0-9.]+) deg ([0-9.]+)\' ([0-9.]+)"!', $coordinates, $matches)) {
return false;
}

return intval($matches[1]) + (intval($matches[2]) / 60) + (floatval($matches[3]) / 3600);
}
}
}
41 changes: 40 additions & 1 deletion lib/PHPExif/Adapter/Native.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ public function getExifFromFile($file)
*/
public function getIptcData($file)
{
$size = getimagesize($file, $info);
getimagesize($file, $info);
$arrData = array();
if (isset($info['APP13'])) {
$iptc = iptcparse($info['APP13']);
Expand Down Expand Up @@ -262,6 +262,18 @@ public function mapData(array $source)
$exposureTime = '1/' . round($denominator);
}

$gpsLocation = false;
if (isset($source['GPSLatitudeRef']) && isset($source['GPSLongitudeRef'])) {
$latitude = $this->extractGPSCoordinate($source['GPSLatitude']);
$longitude = $this->extractGPSCoordinate($source['GPSLongitude']);

$gpsLocation = sprintf(
'%s,%s',
(strtoupper($source['GPSLatitudeRef'][0]) === 'S' ? -1 : 1) * $latitude,
(strtoupper($source['GPSLongitudeRef'][0]) === 'W' ? -1 : 1) * $longitude
);
}

return array(
Exif::APERTURE => (!isset($source[self::SECTION_COMPUTED]['ApertureFNumber'])) ?
false : $source[self::SECTION_COMPUTED]['ApertureFNumber'],
Expand Down Expand Up @@ -301,6 +313,7 @@ public function mapData(array $source)
Exif::VERTICAL_RESOLUTION => $vertResolution,
Exif::WIDTH => (!isset($source[self::SECTION_COMPUTED]['Width'])) ?
false : $source[self::SECTION_COMPUTED]['Width'],
Exif::GPS => $gpsLocation,
);

$arrMapping = array(
Expand Down Expand Up @@ -345,4 +358,30 @@ public function mapData(array $source)

return $mappedData;
}

/**
* Extract GPS coordinates from components array
*
* @param array $components
* @return float
*/
protected function extractGPSCoordinate(array $components)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you unit test this method? Coverage is brought down now, which I want to avoid.

{
$components = array_map(array($this, 'normalizeGPSComponent'), $components);

return intval($components[0]) + (intval($components[1]) / 60) + (floatval($components[2]) / 3600);
}

/**
* Normalize GPS coordinates components
*
* @param mixed $component
* @return int|float
*/
protected function normalizeGPSComponent($component)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you unit test this method? Coverage is brought down now, which I want to avoid.

{
$parts = explode('/', $component);

return count($parts) === 1 ? $parts[0] : (int) reset($parts) / (int) end($parts);
}
}
29 changes: 22 additions & 7 deletions lib/PHPExif/Exif.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class Exif
const TITLE = 'title';
const VERTICAL_RESOLUTION = 'verticalResolution';
const WIDTH = 'width';
const GPS = 'gps';

/**
* The mapped EXIF data
Expand Down Expand Up @@ -427,7 +428,7 @@ public function getCreationDate()

return $this->data[self::CREATION_DATE];
}

/**
* Returns the colorspace, if it exists
*
Expand All @@ -438,10 +439,10 @@ public function getColorSpace()
if (!isset($this->data[self::COLORSPACE])) {
return false;
}

return $this->data[self::COLORSPACE];
}

/**
* Returns the mimetype, if it exists
*
Expand All @@ -452,21 +453,21 @@ public function getMimeType()
if (!isset($this->data[self::MIMETYPE])) {
return false;
}

return $this->data[self::MIMETYPE];
}

/**
* Returns the filesize, if it exists
*
*
* @return integer
*/
public function getFileSize()
{
if (!isset($this->data[self::FILESIZE])) {
return false;
}

return $this->data[self::FILESIZE];
}

Expand All @@ -483,4 +484,18 @@ public function getOrientation()

return $this->data[self::ORIENTATION];
}

/**
* 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];
}
}
42 changes: 42 additions & 0 deletions tests/PHPExif/Adapter/ExiftoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,48 @@ public function testMapDataFocalLengthIsCalculated()
$this->assertEquals(18, $result[\PHPExif\Exif::FOCAL_LENGTH]);
}

/**
* @group exiftool
* @covers \PHPExif\Adapter\Exiftool::setNumeric
* @covers \PHPExif\Adapter\Exiftool::mapData
* @covers \PHPExif\Adapter\Exiftool::extractGPSCoordinates
*/
public function testMapDataCreationDegGPSIsCalculated()
{
$this->adapter->setNumeric(false);
$result = $this->adapter->mapData(
array(
'GPSLatitude' => '40 deg 20\' 0.42857" N',
'GPSLatitudeRef' => 'North',
'GPSLongitude' => '20 deg 10\' 2.33333" W',
'GPSLongitudeRef' => 'West',
)
);

$expected = '40.333452380556,-20.167314813889';
$this->assertEquals($expected, $result[\PHPExif\Exif::GPS]);
}

/**
* @group exiftool
* @covers \PHPExif\Adapter\Exiftool::mapData
* @covers \PHPExif\Adapter\Exiftool::extractGPSCoordinates
*/
public function testMapDataCreationNumericGPSIsCalculated()
{
$result = $this->adapter->mapData(
array(
'GPSLatitude' => '40.333452381',
'GPSLatitudeRef' => 'North',
'GPSLongitude' => '20.167314814',
'GPSLongitudeRef' => 'West',
)
);

$expected = '40.333452381,-20.167314814';
$this->assertEquals($expected, $result[\PHPExif\Exif::GPS]);
}

/**
* @group exiftool
* @covers \PHPExif\Adapter\Exiftool::getCliOutput
Expand Down
21 changes: 21 additions & 0 deletions tests/PHPExif/Adapter/NativeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,4 +319,25 @@ public function testMapDataCreationDateIsConvertedToDatetime()

$this->assertInstanceOf('DateTime', $result[\PHPExif\Exif::CREATION_DATE]);
}

/**
* @group native
* @covers \PHPExif\Adapter\Native::mapData
* @covers \PHPExif\Adapter\Native::extractGPSCoordinate
* @covers \PHPExif\Adapter\Native::normalizeGPSComponent
*/
public function testMapDataCreationGPSIsCalculated()
{
$result = $this->adapter->mapData(
array(
'GPSLatitude' => array('40/1', '20/1', '15/35'),
'GPSLatitudeRef' => 'N',
'GPSLongitude' => array('20/1', '10/1', '35/15'),
'GPSLongitudeRef' => 'W',
)
);

$expected = '40.333452380952,-20.167314814815';
$this->assertEquals($expected, $result[\PHPExif\Exif::GPS]);
}
}
18 changes: 15 additions & 3 deletions tests/PHPExif/ExifTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ public function testGetJobtitle()
$this->exif->setData($data);
$this->assertEquals($expected, $this->exif->getJobtitle());
}

/**
* @group exif
* @covers \PHPExif\Exif::getColorSpace
Expand All @@ -413,7 +413,7 @@ public function testGetColorSpace()
$this->exif->setData($data);
$this->assertEquals($expected, $this->exif->getColorSpace());
}

/**
* @group exif
* @covers \PHPExif\Exif::getMimeType
Expand All @@ -425,7 +425,7 @@ public function testGetMimeType()
$this->exif->setData($data);
$this->assertEquals($expected, $this->exif->getMimeType());
}

/**
* @group exif
* @covers \PHPExif\Exif::getFileSize
Expand All @@ -446,6 +446,18 @@ public function testGetOrientation()
$this->assertEquals($expected, $this->exif->getOrientation());
}

/**
* @group exif
* @covers \PHPExif\Exif::getGPS
*/
public function testGetGPS()
{
$expected = '40.333452380556,-20.167314813889';
$data[\PHPExif\Exif::GPS] = $expected;
$this->exif->setData($data);
$this->assertEquals($expected, $this->exif->getGPS());
}

/**
* Test that the values returned by both adapters are equal
*/
Expand Down