* @link https://getkirby.com * @copyright Bastian Allgeier * @license https://opensource.org/licenses/MIT */ class Image extends File { protected Exif|null $exif = null; protected Dimensions|null $dimensions = null; public static array $resizableTypes = [ 'avif', 'jpg', 'jpeg', 'gif', 'png', 'webp' ]; public static array $viewableTypes = [ 'avif', 'jpg', 'jpeg', 'gif', 'png', 'svg', 'webp' ]; /** * Validation rules to be used for `::match()` */ public static array $validations = [ 'maxsize' => ['size', 'max'], 'minsize' => ['size', 'min'], 'maxwidth' => ['width', 'max'], 'minwidth' => ['width', 'min'], 'maxheight' => ['height', 'max'], 'minheight' => ['height', 'min'], 'orientation' => ['orientation', 'same'] ]; /** * Returns the `` tag for the image object */ public function __toString(): string { return $this->html(); } /** * Returns the dimensions of the file if possible */ public function dimensions(): Dimensions { if ($this->dimensions !== null) { return $this->dimensions; } if (in_array($this->mime(), [ 'image/avif', 'image/gif', 'image/jpeg', 'image/jp2', 'image/png', 'image/webp' ])) { return $this->dimensions = Dimensions::forImage($this->root); } if ($this->extension() === 'svg') { return $this->dimensions = Dimensions::forSvg($this->root); } return $this->dimensions = new Dimensions(0, 0); } /** * Returns the exif object for this file (if image) */ public function exif(): Exif { return $this->exif ??= new Exif($this); } /** * Returns the height of the asset */ public function height(): int { return $this->dimensions()->height(); } /** * Converts the file to html */ public function html(array $attr = []): string { $model = match (true) { $this->model instanceof FileVersion => $this->model->original(), default => $this->model }; // if no alt text explicitly provided, // try to infer from model content file if ( $model !== null && method_exists($model, 'content') === true && $model->content() instanceof Content && $model->content()->get('alt')->isNotEmpty() === true ) { $attr['alt'] ??= $model->content()->get('alt')->value(); } if ($url = $this->url()) { return Html::img($url, $attr); } throw new LogicException('Calling Image::html() requires that the URL property is not null'); } /** * Returns the PHP imagesize array */ public function imagesize(): array { return getimagesize($this->root); } /** * Checks if the dimensions of the asset are portrait */ public function isPortrait(): bool { return $this->dimensions()->portrait(); } /** * Checks if the dimensions of the asset are landscape */ public function isLandscape(): bool { return $this->dimensions()->landscape(); } /** * Checks if the dimensions of the asset are square */ public function isSquare(): bool { return $this->dimensions()->square(); } /** * Checks if the file is a resizable image */ public function isResizable(): bool { return in_array($this->extension(), static::$resizableTypes) === true; } /** * Checks if a preview can be displayed for the file * in the Panel or in the frontend */ public function isViewable(): bool { return in_array($this->extension(), static::$viewableTypes) === true; } /** * Returns the ratio of the asset */ public function ratio(): float { return $this->dimensions()->ratio(); } /** * Returns the orientation as string * `landscape` | `portrait` | `square` */ public function orientation(): string|false { return $this->dimensions()->orientation(); } /** * Converts the object to an array */ public function toArray(): array { $array = array_merge(parent::toArray(), [ 'dimensions' => $this->dimensions()->toArray(), 'exif' => $this->exif()->toArray(), ]); ksort($array); return $array; } /** * Returns the width of the asset */ public function width(): int { return $this->dimensions()->width(); } }