julienmonnerie/kirby/src/Image/Exif.php

251 lines
4.5 KiB
PHP
Raw Normal View History

2022-06-17 17:51:59 +02:00
<?php
namespace Kirby\Image;
use Kirby\Toolkit\V;
/**
* Reads exif data from a given image object
*
* @package Kirby Image
* @author Bastian Allgeier <bastian@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
*/
class Exif
{
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* The parent image object
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected Image $image;
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* The raw exif array
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected array $data = [];
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* The camera object with model and make
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected Camera|null $camera = null;
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* The location object
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected Location|null $location = null;
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* The timestamp
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected string|null $timestamp = null;
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* The exposure value
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected string|null $exposure = null;
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* The aperture value
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected string|null $aperture = null;
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* ISO value
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected string|null $iso = null;
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* Focal length
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected string|null $focalLength = null;
2022-08-31 15:02:43 +02:00
/**
2022-12-19 14:56:05 +01:00
* Color or black/white
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected bool|null $isColor = null;
2022-08-31 15:02:43 +02:00
public function __construct(Image $image)
{
$this->image = $image;
$this->data = $this->read();
$this->parse();
}
/**
* Returns the raw data array from the parser
*/
public function data(): array
{
return $this->data;
}
/**
* Returns the Camera object
*/
2022-12-19 14:56:05 +01:00
public function camera(): Camera
2022-08-31 15:02:43 +02:00
{
if ($this->camera !== null) {
return $this->camera;
}
return $this->camera = new Camera($this->data);
}
/**
* Returns the location object
*/
2022-12-19 14:56:05 +01:00
public function location(): Location
2022-08-31 15:02:43 +02:00
{
if ($this->location !== null) {
return $this->location;
}
return $this->location = new Location($this->data);
}
/**
* Returns the timestamp
*/
2022-12-19 14:56:05 +01:00
public function timestamp(): string|null
2022-08-31 15:02:43 +02:00
{
return $this->timestamp;
}
/**
* Returns the exposure
*/
2022-12-19 14:56:05 +01:00
public function exposure(): string|null
2022-08-31 15:02:43 +02:00
{
return $this->exposure;
}
/**
* Returns the aperture
*/
2022-12-19 14:56:05 +01:00
public function aperture(): string|null
2022-08-31 15:02:43 +02:00
{
return $this->aperture;
}
/**
* Returns the iso value
*/
2022-12-19 14:56:05 +01:00
public function iso(): string|null
2022-08-31 15:02:43 +02:00
{
return $this->iso;
}
/**
* Checks if this is a color picture
*/
2022-12-19 14:56:05 +01:00
public function isColor(): bool|null
2022-08-31 15:02:43 +02:00
{
return $this->isColor;
}
/**
* Checks if this is a bw picture
*/
2022-12-19 14:56:05 +01:00
public function isBW(): bool|null
2022-08-31 15:02:43 +02:00
{
return ($this->isColor !== null) ? $this->isColor === false : null;
}
/**
* Returns the focal length
*/
2022-12-19 14:56:05 +01:00
public function focalLength(): string|null
2022-08-31 15:02:43 +02:00
{
return $this->focalLength;
}
/**
* Read the exif data of the image object if possible
*/
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
*/
protected function computed(): array
{
return $this->data['COMPUTED'] ?? [];
}
/**
2022-12-19 14:56:05 +01:00
* Parses and stores all relevant exif data
2022-08-31 15:02:43 +02:00
*/
2022-12-19 14:56:05 +01:00
protected function parse(): void
2022-08-31 15:02:43 +02:00
{
$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
*/
2022-12-19 14:56:05 +01:00
protected function parseTimestamp(): string
2022-08-31 15:02:43 +02:00
{
if (isset($this->data['DateTimeOriginal']) === true) {
2022-12-19 14:56:05 +01:00
if ($time = strtotime($this->data['DateTimeOriginal'])) {
return (string)$time;
}
2022-08-31 15:02:43 +02:00
}
return $this->data['FileDateTime'] ?? $this->image->modified();
}
/**
* Return the focal length
*/
2022-12-19 14:56:05 +01:00
protected function parseFocalLength(): string|null
2022-08-31 15:02:43 +02:00
{
2022-12-19 14:56:05 +01:00
return $this->data['FocalLength'] ??
$this->data['FocalLengthIn35mmFilm'] ??
null;
2022-08-31 15:02:43 +02:00
}
/**
* Converts the object into a nicely readable array
*/
public function toArray(): array
{
return [
2022-12-19 14:56:05 +01:00
'camera' => $this->camera()->toArray(),
'location' => $this->location()->toArray(),
2022-08-31 15:02:43 +02:00
'timestamp' => $this->timestamp(),
'exposure' => $this->exposure(),
'aperture' => $this->aperture(),
'iso' => $this->iso(),
'focalLength' => $this->focalLength(),
'isColor' => $this->isColor()
];
}
/**
* Improved `var_dump` output
*/
public function __debugInfo(): array
{
return array_merge($this->toArray(), [
'camera' => $this->camera(),
'location' => $this->location()
]);
}
2022-06-17 17:51:59 +02:00
}