* @link https://getkirby.com * @copyright Bastian Allgeier * @license https://opensource.org/licenses/MIT */ class Exif { /** * the parent image object * @var \Kirby\Image\Image */ protected $image; /** * the raw exif array * @var array */ protected $data = []; /** * the camera object with model and make * @var Camera */ protected $camera; /** * the location object * @var Location */ protected $location; /** * the timestamp * * @var string */ protected $timestamp; /** * the exposure value * * @var string */ protected $exposure; /** * the aperture value * * @var string */ protected $aperture; /** * iso value * * @var string */ protected $iso; /** * focal length * * @var string */ protected $focalLength; /** * color or black/white * @var bool */ protected $isColor; /** * Constructor * * @param \Kirby\Image\Image $image */ public function __construct(Image $image) { $this->image = $image; $this->data = $this->read(); $this->parse(); } /** * Returns the raw data array from the parser * * @return array */ public function data(): array { return $this->data; } /** * Returns the Camera object * * @return \Kirby\Image\Camera|null */ public function camera() { if ($this->camera !== null) { return $this->camera; } return $this->camera = new Camera($this->data); } /** * Returns the location object * * @return \Kirby\Image\Location|null */ public function location() { if ($this->location !== null) { return $this->location; } return $this->location = new Location($this->data); } /** * Returns the timestamp * * @return string|null */ public function timestamp() { return $this->timestamp; } /** * Returns the exposure * * @return string|null */ public function exposure() { return $this->exposure; } /** * Returns the aperture * * @return string|null */ public function aperture() { return $this->aperture; } /** * Returns the iso value * * @return int|null */ public function iso() { return $this->iso; } /** * Checks if this is a color picture * * @return bool|null */ public function isColor() { return $this->isColor; } /** * Checks if this is a bw picture * * @return bool|null */ public function isBW(): ?bool { return ($this->isColor !== null) ? $this->isColor === false : null; } /** * Returns the focal length * * @return string|null */ public function focalLength() { return $this->focalLength; } /** * Read the exif data of the image object if possible * * @return mixed */ protected function read(): array { // @codeCoverageIgnoreStart if (function_exists('exif_read_data') === false) { return []; } // @codeCoverageIgnoreEnd $data = @exif_read_data($this->image->root()); return is_array($data) ? $data : []; } /** * Get all computed data * * @return array */ protected function computed(): array { return $this->data['COMPUTED'] ?? []; } /** * Pareses and stores all relevant exif data */ protected function parse() { $this->timestamp = $this->parseTimestamp(); $this->exposure = $this->data['ExposureTime'] ?? null; $this->iso = $this->data['ISOSpeedRatings'] ?? null; $this->focalLength = $this->parseFocalLength(); $this->aperture = $this->computed()['ApertureFNumber'] ?? null; $this->isColor = V::accepted($this->computed()['IsColor'] ?? null); } /** * Return the timestamp when the picture has been taken * * @return string|int */ protected function parseTimestamp() { if (isset($this->data['DateTimeOriginal']) === true) { return strtotime($this->data['DateTimeOriginal']); } return $this->data['FileDateTime'] ?? $this->image->modified(); } /** * Return the focal length * * @return string|null */ protected function parseFocalLength() { return $this->data['FocalLength'] ?? $this->data['FocalLengthIn35mmFilm'] ?? null; } /** * Converts the object into a nicely readable array * * @return array */ public function toArray(): array { return [ 'camera' => $this->camera() ? $this->camera()->toArray() : null, 'location' => $this->location() ? $this->location()->toArray() : null, 'timestamp' => $this->timestamp(), 'exposure' => $this->exposure(), 'aperture' => $this->aperture(), 'iso' => $this->iso(), 'focalLength' => $this->focalLength(), 'isColor' => $this->isColor() ]; } /** * Improved `var_dump` output * * @return array */ public function __debugInfo(): array { return array_merge($this->toArray(), [ 'camera' => $this->camera(), 'location' => $this->location() ]); } }