MarkL
MarkL

Reputation: 25

Parsing EXIF's "ExposureTime" using PHP

Re,

One photo with exposure being 1/640 has the EXIF field of "ExposureTime" eq. "15625/10000000". I am not sure why some photos display this value in a readable format (e.g., "1/100"), but I need to convert this "15625" back to "1/640". How? :)

Thanks.

Upvotes: 1

Views: 2280

Answers (4)

Sebastien B.
Sebastien B.

Reputation: 61

I improved upon ZZ Coders implementation with a few sanity checks and special cases. It seems to work well with my images with several special cases thrown at it. Please let me know if there are any issues and we'll improve it.

// Exposure Time
$exif = exif_read_data($fullPath, 'IFD0', true);
$arrExposureTime = explode('/', $exif['EXIF']['ExposureTime']);
// Sanity check for zero denominator.
if ($arrExposureTime[1] == 0) {
    $ExposureTime = '<sup>1</sup>/? sec';
// In case numerator is zero.
} elseif ($arrExposureTime[0] == 0) {
    $ExposureTime = '<sup>0</sup>/' . $arrExposureTime[1] . ' sec';
// When denominator is 1, display time in whole seconds, minutes, and/or hours.
} elseif ($arrExposureTime[1] == 1) {
    // In the Seconds range.
    if ($arrExposureTime[0] < 60) {
        $ExposureTime = $arrExposureTime[0] . ' s';
    // In the Minutes range.
    } elseif (($arrExposureTime[0] >= 60) && ($arrExposureTime[0] < 3600)) {
        $ExposureTime = gmdate("i\m:s\s", $arrExposureTime[0]);
    // In the Hours range.
    } else {
        $ExposureTime = gmdate("H\h:i\m:s\s", $arrExposureTime[0]);
    }
// When inverse is evenly divisable, show reduced fractional exposure.
} elseif (($arrExposureTime[1] % $arrExposureTime[0]) == 0) {
    $ExposureTime = '<sup>1</sup>/' . $arrExposureTime[1]/$arrExposureTime[0] . ' sec';
// If the value is greater or equal to 3/10, which is the smallest standard
// exposure value that doesn't divid evenly, show it in decimal form.
} elseif (($arrExposureTime[0]/$arrExposureTime[1]) >= 3/10) { 
    $ExposureTime = round(($arrExposureTime[0]/$arrExposureTime[1]), 1) . ' sec';
// If all else fails, just display it as it was found.
} else {
    $ExposureTime = '<sup>' . $arrExposureTime[0] . '</sup>/' . $arrExposureTime[1] . ' sec';
}

Upvotes: 4

Abe Voelker
Abe Voelker

Reputation: 31594

You can use Euclid's algorithm to find the greatest common divisor, which will help you reduce the fraction.

Upvotes: 0

ZZ Coder
ZZ Coder

Reputation: 75496

This is the code I use to normalize the exposure,

                    if (($bottom % $top) == 0) {
                            $data = '1/'.round($bottom/$top, 0).' sec';
                    }       else {
                            if ($bottom == 1) {
                                    $data = $top.' sec';
                            } else {
                                    $data = $top.'/'.$bottom.' sec';
                            }
                    }

It handles most exposures correctly but I see some weird ones once a while.

Upvotes: 0

Dean Harding
Dean Harding

Reputation: 72668

It's simple mathematics: simply divide the top and bottom of the fraction by the top value.

  15625 / 10000000
= (15625/15625) / (10000000/15625)
= 1 / 640

In PHP, you can do it like this:

$exposure = "15625/10000000";
$parts = explode("/", $exposure);
$exposure = implode("/", array(1, $parts[1]/$parts[0]));

echo $exposure;

Upvotes: 5

Related Questions