Simplify the ExposureTime fraction in ExifUtil::getFormattedExifData()
authorTim Düsterhus <duesterhus@woltlab.com>
Mon, 24 Apr 2023 11:25:19 +0000 (13:25 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Mon, 24 Apr 2023 11:26:27 +0000 (13:26 +0200)
see https://www.woltlab.com/community/thread/298320-fehlerhafte-exif-daten/

wcfsetup/install/files/lib/util/ExifUtil.class.php

index 81a6a92a80a4551c10e1c8329d36e3bcf6c72b54..8878f5dee340f9024b59be698b87f4517a42c3ba 100644 (file)
@@ -211,7 +211,7 @@ final class ExifUtil
 
         // unit is second (unsigned rational)
         if (isset($rawExifData['ExposureTime']) && \is_string($rawExifData['ExposureTime'])) {
-            $exifData['ExposureTime'] = $rawExifData['ExposureTime'];
+            $exifData['ExposureTime'] = self::simplifyRational($rawExifData['ExposureTime']);
         }
         // actual F-number(F-stop) of lens when the image was taken (unsigned rational)
         if (isset($rawExifData['FNumber']) && \is_string($rawExifData['FNumber'])) {
@@ -254,11 +254,8 @@ final class ExifUtil
 
     /**
      * Converts the format of exif geo tagging coordinates.
-     *
-     * @param string $coordinate
-     * @return  double
      */
-    private static function convertCoordinateToDecimal($coordinate)
+    private static function convertCoordinateToDecimal(string $coordinate): float
     {
         $result = 0.0;
         $coordinateData = \explode('/', $coordinate);
@@ -275,11 +272,8 @@ final class ExifUtil
 
     /**
      * Converts a exif rational value to a float.
-     *
-     * @param string $rational
-     * @return  float
      */
-    private static function convertExifRational($rational)
+    private static function convertExifRational(string $rational): float
     {
         $data = \explode('/', $rational);
         if (\count($data) == 1) {
@@ -294,4 +288,32 @@ final class ExifUtil
 
         return \floatval($data[0]) / $data[1];
     }
+
+    private static function simplifyRational(string $rational): string
+    {
+        $data = \explode('/', $rational);
+        if (\count($data) == 1) {
+            return $data;
+        }
+
+        $numerator = $data[0];
+        $denonimator = $data[1];
+        $gcd = self::gcd($numerator, $denonimator);
+
+        return \sprintf('%d/%d', $numerator / $gcd, $denonimator / $gcd);
+    }
+
+    /**
+     * Implements the Euclidian Algorithm to calculate the GCD.
+     */
+    private static function gcd(int $a, int $b)
+    {
+        while ($b != 0) {
+            $t = $b;
+            $b = $a % $b;
+            $a = $t;
+        }
+
+        return $a;
+    }
 }