Skip to content

Commit

Permalink
Fix 1367 (#44)
Browse files Browse the repository at this point in the history
* Accept 0 degrees/minutes/seconds

* Fix argument types of some set methods

* Add width and height data

Co-authored-by: Matthias Nagel <[email protected]>
  • Loading branch information
kamil4 and nagmat84 authored Jul 6, 2022
1 parent fcfa13e commit f908413
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 103 deletions.
11 changes: 10 additions & 1 deletion lib/PHPExif/Adapter/ImageMagick.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,16 @@ public function getExifFromFile(string $file) : Exif
$data_filename = basename($file);
$data_filesize = filesize($file);
$mimeType = mime_content_type($file);
$additional_data = array('MimeType' => $mimeType, 'filesize' => $data_filesize, 'filename' => $data_filename);
$data_width = $im->getImageWidth();
$data_height = $im->getImageHeight();
$additional_data = [
'MimeType' => $mimeType,
'filesize' => $data_filesize,
'filename' => $data_filename,
'width' => $data_width,
'height' => $data_height
];

$data = array_merge($data_exif, $additional_data);

// map the data:
Expand Down
20 changes: 10 additions & 10 deletions lib/PHPExif/Exif.php
Original file line number Diff line number Diff line change
Expand Up @@ -793,10 +793,10 @@ public function getFileSize() : int|false
/**
* Sets the filesize
*
* @param string $value
* @param int $value
* @return Exif
*/
public function setFileSize(string $value) : Exif
public function setFileSize(int $value) : Exif
{
$this->data[self::FILESIZE] = $value;

Expand Down Expand Up @@ -942,10 +942,10 @@ public function getMake() : string|false
/**
* Sets the altitude value
*
* @param string $value
* @param float $value
* @return Exif
*/
public function setAltitude(string $value) : Exif
public function setAltitude(float $value) : Exif
{
$this->data[self::ALTITUDE] = $value;

Expand All @@ -969,10 +969,10 @@ public function getAltitude() : float|false
/**
* Sets the altitude value
*
* @param string $value
* @param float $value
* @return Exif
*/
public function setLongitude(string $value) : Exif
public function setLongitude(float $value) : Exif
{
$this->data[self::LONGITUDE] = $value;

Expand All @@ -996,10 +996,10 @@ public function getLongitude() : float|false
/**
* Sets the latitude value
*
* @param string $value
* @param float $value
* @return Exif
*/
public function setLatitude(string $value) : Exif
public function setLatitude(float $value) : Exif
{
$this->data[self::LATITUDE] = $value;

Expand All @@ -1023,10 +1023,10 @@ public function getLatitude() : float|false
/**
* Sets the imgDirection value
*
* @param string $value
* @param float $value
* @return Exif
*/
public function setImgDirection(string $value) : Exif
public function setImgDirection(float $value) : Exif
{
$this->data[self::IMGDIRECTION] = $value;

Expand Down
42 changes: 20 additions & 22 deletions lib/PHPExif/Mapper/Exiftool.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,36 +281,40 @@ public function mapRawData(array $data) : array
break;
case self::GPSLATITUDE_QUICKTIME:
$value = $this->extractGPSCoordinates($value);
if ($value === false) {
continue 2;
}
break;
case self::GPSLATITUDE:
$latitudeRef = !array_key_exists('GPS:GPSLatitudeRef', $data) ?
'N' : $data['GPS:GPSLatitudeRef'][0];
$value = $this->extractGPSCoordinates($value);
if ($value !== false) {
$value = (strtoupper($latitudeRef) === 'S' ? -1.0 : 1.0) * $value;
} else {
$value = false;
if ($value === false) {
continue 2;
}

$value *= strtoupper($latitudeRef) === 'S' ? -1 : 1;
break;
case self::GPSLONGITUDE_QUICKTIME:
$value = $this->extractGPSCoordinates($value);
if ($value === false) {
continue 2;
}
break;
case self::GPSLONGITUDE:
$longitudeRef = !array_key_exists('GPS:GPSLongitudeRef', $data) ?
'E' : $data['GPS:GPSLongitudeRef'][0];
$value = $this->extractGPSCoordinates($value);
if ($value !== false) {
$value = (strtoupper($longitudeRef) === 'W' ? -1 : 1) * $value;
$value = $this->extractGPSCoordinates($value);
if ($value === false) {
continue 2;
}

$value *= strtoupper($longitudeRef) === 'W' ? -1 : 1;
break;
case self::GPSALTITUDE:
$flip = 1;
if (array_key_exists('GPS:GPSAltitudeRef', $data)) {
$flip = ($data['GPS:GPSAltitudeRef'] === '1') ? -1 : 1;
}
$value = $flip * (float) $value;
$value = $flip * (float) $value;
break;
case self::GPSALTITUDE_QUICKTIME:
$flip = 1;
Expand All @@ -322,7 +326,7 @@ public function mapRawData(array $data) : array
case self::IMAGEHEIGHT_VIDEO:
case self::IMAGEWIDTH_VIDEO:
preg_match("#^(\d+)[^\d]+(\d+)$#", $value, $matches);
$value_splitted = array_slice($matches, 1);
$value_split = array_slice($matches, 1);
$rotate = false;
if (array_key_exists('Composite:Rotation', $data)) {
if ($data['Composite:Rotation'] === '90' || $data['Composite:Rotation'] === '270') {
Expand All @@ -331,16 +335,16 @@ public function mapRawData(array $data) : array
}
if (!array_key_exists(Exif::WIDTH, $mappedData)) {
if (!($rotate)) {
$mappedData[Exif::WIDTH] = intval($value_splitted[0]);
$mappedData[Exif::WIDTH] = intval($value_split[0]);
} else {
$mappedData[Exif::WIDTH] = intval($value_splitted[1]);
$mappedData[Exif::WIDTH] = intval($value_split[1]);
}
}
if (!array_key_exists(Exif::HEIGHT, $mappedData)) {
if (!($rotate)) {
$mappedData[Exif::HEIGHT] = intval($value_splitted[1]);
$mappedData[Exif::HEIGHT] = intval($value_split[1]);
} else {
$mappedData[Exif::HEIGHT] = intval($value_splitted[0]);
$mappedData[Exif::HEIGHT] = intval($value_split[0]);
}
}
continue 2;
Expand Down Expand Up @@ -374,13 +378,7 @@ public function mapRawData(array $data) : array

// add GPS coordinates, if available
if ((isset($mappedData[Exif::LATITUDE])) && (isset($mappedData[Exif::LONGITUDE]))) {
if (($mappedData[Exif::LATITUDE]!==false) && $mappedData[Exif::LONGITUDE]!==false) {
$mappedData[Exif::GPS] = sprintf('%s,%s', $mappedData[Exif::LATITUDE], $mappedData[Exif::LONGITUDE]);
} else {
$mappedData[Exif::GPS] = false;
}
} else {
unset($mappedData[Exif::GPS]);
$mappedData[Exif::GPS] = sprintf('%s,%s', $mappedData[Exif::LATITUDE], $mappedData[Exif::LONGITUDE]);
}

return $mappedData;
Expand Down
12 changes: 6 additions & 6 deletions lib/PHPExif/Mapper/FFprobe.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ public function mapRawData(array $data) : array
break;
case self::FRAMERATE:
$value = $this->normalizeComponent($value);
if ($value === false) {
continue 2;
}
break;
case self::GPSLATITUDE:
case self::GPSLONGITUDE:
Expand All @@ -168,7 +171,6 @@ public function mapRawData(array $data) : array
$mappedData[Exif::LATITUDE] = $location_data['latitude'];
$mappedData[Exif::LONGITUDE] = $location_data['longitude'];
$mappedData[Exif::ALTITUDE] = $location_data['altitude'];
//$value = $this->normalizeComponent($value);
continue 2;
}

Expand All @@ -179,8 +181,6 @@ public function mapRawData(array $data) : array
// add GPS coordinates, if available
if ((isset($mappedData[Exif::LATITUDE])) && (isset($mappedData[Exif::LONGITUDE]))) {
$mappedData[Exif::GPS] = sprintf('%s,%s', $mappedData[Exif::LATITUDE], $mappedData[Exif::LONGITUDE]);
} else {
unset($mappedData[Exif::GPS]);
}

// Swap width and height if needed
Expand Down Expand Up @@ -236,9 +236,9 @@ protected function isFieldKnown(string &$field) : bool
* Normalize component
*
* @param string $rational
* @return float
* @return float|false
*/
protected function normalizeComponent(string $rational) : float
protected function normalizeComponent(string $rational) : float|false
{
$parts = explode('/', $rational, 2);
if (count($parts) === 1) {
Expand All @@ -247,7 +247,7 @@ protected function normalizeComponent(string $rational) : float
// case part[1] is 0, div by 0 is forbidden.
// Catch case of one entry not being numeric
if ($parts[1] === '0' || !is_numeric($parts[0]) || !is_numeric($parts[1])) {
return (float) 0;
return false;
}
return (float) $parts[0] / $parts[1];
}
Expand Down
72 changes: 44 additions & 28 deletions lib/PHPExif/Mapper/ImageMagick.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ class ImageMagick implements MapperInterface
const GPSALTITUDE = 'exif:GPSAltitude';
const IMAGEHEIGHT = 'exif:PixelYDimension';
const IMAGEHEIGHT_PNG = 'png:IHDR.width,height';
const HEIGHT = 'height';
const IMAGEWIDTH = 'exif:PixelXDimension';
const IMAGEWIDTH_PNG = 'png:IHDR.width,height';
const WIDTH = 'width';
const IMGDIRECTION = 'exif:GPSImgDirection';
const ISO = 'exif:PhotographicSensitivity';
const LENS = 'exif:LensModel';
Expand Down Expand Up @@ -78,8 +80,10 @@ class ImageMagick implements MapperInterface
self::IMGDIRECTION => Exif::IMGDIRECTION,
self::IMAGEHEIGHT => Exif::HEIGHT,
self::IMAGEHEIGHT_PNG => Exif::HEIGHT,
self::HEIGHT => Exif::HEIGHT,
self::IMAGEWIDTH => Exif::WIDTH,
self::IMAGEWIDTH_PNG => Exif::WIDTH,
self::WIDTH => Exif::WIDTH,
self::ISO => Exif::ISO,
self::LENS => Exif::LENS,
self::MAKE => Exif::MAKE,
Expand Down Expand Up @@ -115,7 +119,11 @@ public function mapRawData(array $data) : array
// manipulate the value if necessary
switch ($field) {
case self::APERTURE:
$value = sprintf('f/%01.1f', $this->normalizeComponent($value));
$value = $this->normalizeComponent($value);
if ($value === false) {
continue 2;
}
$value = sprintf('f/%01.1f', $value);
break;
case self::CREATION_DATE:
if (!isset($mappedData[Exif::CREATION_DATE])
Expand Down Expand Up @@ -150,6 +158,9 @@ public function mapRawData(array $data) : array
break;
case self::EXPOSURETIME:
$value = $this->normalizeComponent($value);
if ($value === false) {
continue 2;
}
// 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) {
Expand All @@ -165,6 +176,9 @@ public function mapRawData(array $data) : array
$value = reset($focalLengthParts);
}
$value = $this->normalizeComponent($value);
if ($value === false) {
continue 2;
}
break;
case self::ISO:
$value = preg_split('/([\s,]+)/', $value)[0];
Expand All @@ -173,38 +187,43 @@ public function mapRawData(array $data) : array
$latitudeRef = !array_key_exists('exif:GPSLatitudeRef', $data) ?
'N' : $data['exif:GPSLatitudeRef'][0];
$value = $this->extractGPSCoordinates($value);
if ($value !== false) {
$value = (strtoupper($latitudeRef) === 'S' ? -1.0 : 1.0) * $value;
} else {
$value = false;
if ($value === false) {
continue 2;
}

$value *= strtoupper($latitudeRef) === 'S' ? -1 : 1;
break;
case self::GPSLONGITUDE:
$longitudeRef = !array_key_exists('exif:GPSLongitudeRef', $data) ?
'E' : $data['exif:GPSLongitudeRef'][0];
$value = $this->extractGPSCoordinates($value);
if ($value !== false) {
$value = (strtoupper($longitudeRef) === 'W' ? -1 : 1) * $value;
if ($value === false) {
continue 2;
}

$value *= strtoupper($longitudeRef) === 'W' ? -1 : 1;
break;
case self::GPSALTITUDE:
$flip = 1;
if (array_key_exists('exif:GPSAltitudeRef', $data)) {
$flip = ($data['exif:GPSAltitudeRef'] === '1') ? -1 : 1;
}
$value = $flip * $this->normalizeComponent($value);
$value = $this->normalizeComponent($value);
if ($value === false) {
continue 2;
}
$value *= $flip;
break;
case self::IMAGEHEIGHT_PNG:
case self::IMAGEWIDTH_PNG:
$value_splitted = explode(",", $value);
$value_split = explode(",", $value);

$mappedData[Exif::WIDTH] = intval($value_splitted[0]);
$mappedData[Exif::HEIGHT] = intval($value_splitted[1]);
$mappedData[Exif::WIDTH] = intval($value_split[0]);
$mappedData[Exif::HEIGHT] = intval($value_split[1]);
continue 2;
case self::IMGDIRECTION:
$value = $this->normalizeComponent($value);
if ($value === false) {
continue 2;
}
break;
}
// set end result
Expand All @@ -213,13 +232,7 @@ public function mapRawData(array $data) : array

// add GPS coordinates, if available
if ((isset($mappedData[Exif::LATITUDE])) && (isset($mappedData[Exif::LONGITUDE]))) {
if (($mappedData[Exif::LATITUDE]!==false) && $mappedData[Exif::LONGITUDE]!==false) {
$mappedData[Exif::GPS] = sprintf('%s,%s', $mappedData[Exif::LATITUDE], $mappedData[Exif::LONGITUDE]);
} else {
$mappedData[Exif::GPS] = false;
}
} else {
unset($mappedData[Exif::GPS]);
$mappedData[Exif::GPS] = sprintf('%s,%s', $mappedData[Exif::LATITUDE], $mappedData[Exif::LONGITUDE]);
}
return $mappedData;
}
Expand All @@ -235,24 +248,27 @@ protected function extractGPSCoordinates(string $coordinates) : float|false
if (is_numeric($coordinates) === true) {
return ((float) $coordinates);
} else {
$m = '!^([1-9][0-9]*\/[1-9][0-9]*), ([1-9][0-9]*\/[1-9][0-9]*), ([1-9][0-9]*\/[1-9][0-9]*)!';
$m = '!^([0-9]+\/[1-9][0-9]*), ([0-9]+\/[1-9][0-9]*), ([0-9]+\/[1-9][0-9]*)!';
if (preg_match($m, $coordinates, $matches) === 0) {
return false;
}
$degree = floatval($this->normalizeComponent($matches[1]));
$minutes = floatval($this->normalizeComponent($matches[2]));
$seconds = floatval($this->normalizeComponent($matches[3]));
return $degree + $minutes / 60 + $seconds / 3600;
$degrees = $this->normalizeComponent($matches[1]);
$minutes = $this->normalizeComponent($matches[2]);
$seconds = $this->normalizeComponent($matches[3]);
if ($degrees === false || $minutes === false || $seconds === false) {
return false;
}
return $degrees + $minutes / 60 + $seconds / 3600;
}
}

/**
* Normalize component
*
* @param string $rational
* @return float
* @return float|false
*/
protected function normalizeComponent(string $rational) : float
protected function normalizeComponent(string $rational) : float|false
{
$parts = explode('/', $rational, 2);
if (count($parts) === 1) {
Expand All @@ -261,7 +277,7 @@ protected function normalizeComponent(string $rational) : float
// case part[1] is 0, div by 0 is forbidden.
// Catch case of one entry not being numeric
if ($parts[1] === '0' || !is_numeric($parts[0]) || !is_numeric($parts[1])) {
return (float) 0;
return false;
}
return (float) $parts[0] / $parts[1];
}
Expand Down
Loading

0 comments on commit f908413

Please sign in to comment.