Skip to content

Commit e3323f0

Browse files
committed
Merge pull request #43 from bonzai/master
Fixed normalization of exposure time
2 parents d10ee92 + 689a0ac commit e3323f0

File tree

6 files changed

+82
-20
lines changed

6 files changed

+82
-20
lines changed

lib/PHPExif/Exif.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,10 @@ public function getExposureMilliseconds()
346346
return false;
347347
}
348348

349+
if (is_numeric($this->data[self::EXPOSURE])) {
350+
return $this->data[self::EXPOSURE] + 0;
351+
}
352+
349353
$exposureParts = explode('/', $this->data[self::EXPOSURE]);
350354

351355
return (int) reset($exposureParts) / (int) end($exposureParts);

lib/PHPExif/Mapper/Exiftool.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,14 @@ public function mapRawData(array $data)
143143
}
144144
break;
145145
case self::EXPOSURETIME:
146-
$value = '1/' . round(1 / $value);
146+
// Based on the source code of Exiftool (PrintExposureTime subroutine):
147+
// http://cpansearch.perl.org/src/EXIFTOOL/Image-ExifTool-9.90/lib/Image/ExifTool/Exif.pm
148+
if ($value < 0.25001 && $value > 0) {
149+
$value = sprintf('1/%d', intval(0.5 + 1 / $value));
150+
} else {
151+
$value = sprintf('%.1f', $value);
152+
$value = preg_replace('/.0$/', '', $value);
153+
}
147154
break;
148155
case self::FOCALLENGTH:
149156
$focalLengthParts = explode(' ', $value);

lib/PHPExif/Mapper/Native.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,18 @@ public function mapRawData(array $data)
150150
}
151151
break;
152152
case self::EXPOSURETIME:
153-
// normalize ExposureTime
154-
// on one test image, it reported "10/300" instead of "1/30"
155-
list($counter, $denominator) = explode('/', $value);
156-
if (intval($counter) !== 1) {
157-
$denominator /= $counter;
153+
if (!is_float($value)) {
154+
$value = $this->normalizeComponent($value);
155+
}
156+
157+
// Based on the source code of Exiftool (PrintExposureTime subroutine):
158+
// http://cpansearch.perl.org/src/EXIFTOOL/Image-ExifTool-9.90/lib/Image/ExifTool/Exif.pm
159+
if ($value < 0.25001 && $value > 0) {
160+
$value = sprintf('1/%d', intval(0.5 + 1 / $value));
161+
} else {
162+
$value = sprintf('%.1f', $value);
163+
$value = preg_replace('/.0$/', '', $value);
158164
}
159-
$value = '1/' . round($denominator);
160165
break;
161166
case self::FOCALLENGTH:
162167
$parts = explode('/', $value);
@@ -217,7 +222,7 @@ protected function isSection($field)
217222
*/
218223
protected function extractGPSCoordinate(array $components)
219224
{
220-
$components = array_map(array($this, 'normalizeGPSComponent'), $components);
225+
$components = array_map(array($this, 'normalizeComponent'), $components);
221226

222227
if (count($components) > 2) {
223228
return intval($components[0]) + (intval($components[1]) / 60) + (floatval($components[2]) / 3600);
@@ -227,12 +232,12 @@ protected function extractGPSCoordinate(array $components)
227232
}
228233

229234
/**
230-
* Normalize GPS coordinates components
235+
* Normalize component
231236
*
232237
* @param mixed $component
233238
* @return int|float
234239
*/
235-
protected function normalizeGPSComponent($component)
240+
protected function normalizeComponent($component)
236241
{
237242
$parts = explode('/', $component);
238243

tests/PHPExif/ExifTest.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,19 @@ public function testGetExposure()
219219
*/
220220
public function testGetExposureMilliseconds()
221221
{
222-
$expected = 1/320;
223-
$data[\PHPExif\Exif::EXPOSURE] = '1/320';
224-
$this->exif->setData($data);
225-
$this->assertEquals($expected, $this->exif->getExposureMilliseconds());
222+
$rawData = array(
223+
array(1/300, '1/300'),
224+
array(0.0025, 0.0025),
225+
);
226+
227+
foreach ($rawData as $data) {
228+
$expected = reset($data);
229+
$value = end($data);
230+
231+
$data[\PHPExif\Exif::EXPOSURE] = $value;
232+
$this->exif->setData($data);
233+
$this->assertEquals($expected, $this->exif->getExposureMilliseconds());
234+
}
226235
}
227236

228237
/**

tests/PHPExif/Mapper/ExiftoolMapperTest.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,19 @@ public function testMapRawDataCorrectlyIgnoresIncorrectCreationDate()
138138
public function testMapRawDataCorrectlyFormatsExposureTime()
139139
{
140140
$rawData = array(
141-
\PHPExif\Mapper\Exiftool::EXPOSURETIME => 1/400,
141+
'1/30' => 10/300,
142+
'1/400' => 2/800,
143+
'1/400' => 1/400,
144+
'0' => 0,
142145
);
143146

144-
$mapped = $this->mapper->mapRawData($rawData);
147+
foreach ($rawData as $expected => $value) {
148+
$mapped = $this->mapper->mapRawData(array(
149+
\PHPExif\Mapper\Exiftool::EXPOSURETIME => $value,
150+
));
145151

146-
$this->assertEquals('1/400', reset($mapped));
152+
$this->assertEquals($expected, reset($mapped));
153+
}
147154
}
148155

149156
/**

tests/PHPExif/Mapper/NativeMapperTest.php

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,19 @@ public function testMapRawDataCorrectlyIgnoresIncorrectDateTimeOriginal()
108108
public function testMapRawDataCorrectlyFormatsExposureTime()
109109
{
110110
$rawData = array(
111-
\PHPExif\Mapper\Native::EXPOSURETIME => '2/800',
111+
'1/30' => 10/300,
112+
'1/400' => 2/800,
113+
'1/400' => 1/400,
114+
'0' => 0,
112115
);
113116

114-
$mapped = $this->mapper->mapRawData($rawData);
117+
foreach ($rawData as $expected => $value) {
118+
$mapped = $this->mapper->mapRawData(array(
119+
\PHPExif\Mapper\Native::EXPOSURETIME => $value,
120+
));
115121

116-
$this->assertEquals('1/400', reset($mapped));
122+
$this->assertEquals($expected, reset($mapped));
123+
}
117124
}
118125

119126
/**
@@ -251,4 +258,27 @@ public function testMapRawDataCorrectlyIgnoresInvalidCreateDate()
251258
$result
252259
);
253260
}
261+
262+
/**
263+
* @group mapper
264+
* @covers \PHPExif\Mapper\Native::normalizeComponent
265+
*/
266+
public function testNormalizeComponentCorrectly()
267+
{
268+
$reflMethod = new \ReflectionMethod('\PHPExif\Mapper\Native', 'normalizeComponent');
269+
$reflMethod->setAccessible(true);
270+
271+
$rawData = array(
272+
'2/800' => 0.0025,
273+
'1/400' => 0.0025,
274+
'0/1' => 0,
275+
'0' => 0,
276+
);
277+
278+
foreach ($rawData as $value => $expected) {
279+
$normalized = $reflMethod->invoke($this->mapper, $value);
280+
281+
$this->assertEquals($expected, $normalized);
282+
}
283+
}
254284
}

0 commit comments

Comments
 (0)