/** * Returns an ExifData instance or NULL if this image does not contain * EXIF Data * * @return img.util.ExifData */ public function exifData() { if (!($seg = $this->segmentsOf('img.io.ExifSegment'))) { return NULL; } // Populate ExifData instance from ExifSegment's raw data with($data = new ExifData(), $raw = $seg[0]->rawData()); $data->setFileName($this->source); $data->setFileSize(-1); $data->setMimeType('image/jpeg'); $data->setMake(NULL === ($l = self::lookup($raw, 'Make')) ? NULL : trim($l)); $data->setModel(NULL === ($l = self::lookup($raw, 'Model')) ? NULL : trim($l)); $data->setSoftware(NULL === ($l = self::lookup($raw, 'Software')) ? NULL : trim($l)); $exif = $raw['Exif_IFD_Pointer']['data']; if ($sof = $this->segmentsOf('img.io.SOFNSegment')) { $data->setWidth($sof[0]->width()); $data->setHeight($sof[0]->height()); } else { $data->setWidth(self::lookup($exif, 'ExifImageWidth')); $data->setHeight(self::lookup($exif, 'ExifImageLength')); } // Aperture is either a FNumber (use directly), otherwise calculate from value if (NULL === ($a = self::lookup($exif, 'FNumber'))) { if (NULL === ($a = self::lookup($exif, 'ApertureValue', 'MaxApertureValue'))) { $data->setApertureFNumber(NULL); } else { sscanf($a, '%d/%d', $n, $frac); $data->setApertureFNumber(sprintf('f/%.1F', exp($n / $frac * log(2) * 0.5))); } } else { sscanf($a, '%d/%d', $n, $frac); $data->setApertureFNumber(sprintf('f/%.1F', $n / $frac)); } $data->setExposureTime(self::lookup($exif, 'ExposureTime')); $data->setExposureProgram(self::lookup($exif, 'ExposureProgram')); $data->setMeteringMode(self::lookup($exif, 'MeteringMode')); $data->setIsoSpeedRatings(self::lookup($exif, 'ISOSpeedRatings')); // Sometimes white balance is in MAKERNOTE - e.g. FUJIFILM's Finepix if (NULL !== ($w = self::lookup($exif, 'WhiteBalance'))) { $data->setWhiteBalance($w); } else { if (isset($exif['MakerNote']) && NULL !== ($w = self::lookup($exif['MakerNote']['data'], 'WhiteBalance'))) { $data->setWhiteBalance($w); } else { $data->setWhiteBalance(NULL); } } // Extract focal length. Some models store "80" as "80/1", rip off // the divisor "1" in this case. if (NULL !== ($l = self::lookup($exif, 'FocalLength'))) { sscanf($l, '%d/%d', $n, $frac); $data->setFocalLength(1 == $frac ? $n : $n . '/' . $frac); } else { $data->setFocalLength(NULL); } // Check for Flash and flashUsed keys if (NULL !== ($f = self::lookup($exif, 'Flash'))) { $data->setFlash($f); } else { $data->setFlash(NULL); } if (NULL !== ($date = self::lookup($exif, 'DateTimeOriginal', 'DateTimeDigitized', 'DateTime'))) { $t = sscanf($date, '%4d:%2d:%2d %2d:%2d:%2d'); $data->setDateTime(new Date(mktime($t[3], $t[4], $t[5], $t[1], $t[2], $t[0]))); } if (NULL !== ($o = self::lookup($exif, 'Orientation'))) { $data->setOrientation($o); } else { $data->setOrientation($data->width / $data->height > 1.0 ? 1 : 5); } return $data; }