Skip to content

Commit

Permalink
Supported format detection (#1330)
Browse files Browse the repository at this point in the history
* Implement data struture for format, media types & file extensions
* Refactor encoder resolving
* Extend type options in encoder methods
* Add DriverInterface::supports()
  • Loading branch information
olivervogel committed Apr 13, 2024
1 parent 5ee087e commit 8f6aabe
Show file tree
Hide file tree
Showing 17 changed files with 991 additions and 58 deletions.
28 changes: 28 additions & 0 deletions src/Drivers/Gd/Driver.php
Expand Up @@ -6,14 +6,18 @@

use Intervention\Image\Drivers\AbstractDriver;
use Intervention\Image\Exceptions\DriverException;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Format;
use Intervention\Image\FileExtension;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ColorProcessorInterface;
use Intervention\Image\Interfaces\ColorspaceInterface;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\FontProcessorInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\MediaType;

class Driver extends AbstractDriver
{
Expand Down Expand Up @@ -138,4 +142,28 @@ public function fontProcessor(): FontProcessorInterface
{
return new FontProcessor();
}

/**
* {@inheritdoc}
*
* @see DriverInterface::supports()
*/
public function supports(string|Format|FileExtension|MediaType $identifier): bool
{
try {
$format = Format::create($identifier);
} catch (NotSupportedException) {
return false;
}

return match ($format) {
Format::JPEG => boolval(imagetypes() & IMG_JPEG),
Format::WEBP => boolval(imagetypes() & IMG_WEBP),
Format::GIF => boolval(imagetypes() & IMG_GIF),
Format::PNG => boolval(imagetypes() & IMG_PNG),
Format::AVIF => boolval(imagetypes() & IMG_AVIF),
Format::BMP => boolval(imagetypes() & IMG_BMP),
default => false,
};
}
}
15 changes: 15 additions & 0 deletions src/Drivers/Imagick/Driver.php
Expand Up @@ -8,14 +8,18 @@
use ImagickPixel;
use Intervention\Image\Drivers\AbstractDriver;
use Intervention\Image\Exceptions\DriverException;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Format;
use Intervention\Image\FileExtension;
use Intervention\Image\Image;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ColorProcessorInterface;
use Intervention\Image\Interfaces\ColorspaceInterface;
use Intervention\Image\Interfaces\DriverInterface;
use Intervention\Image\Interfaces\FontProcessorInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\MediaType;

class Driver extends AbstractDriver
{
Expand Down Expand Up @@ -141,4 +145,15 @@ public function fontProcessor(): FontProcessorInterface
{
return new FontProcessor();
}

public function supports(string|Format|FileExtension|MediaType $identifier): bool
{
try {
$format = Format::create($identifier);
} catch (NotSupportedException) {
return false;
}

return count(Imagick::queryFormats($format->name)) >= 1;
}
}
33 changes: 16 additions & 17 deletions src/Encoders/FileExtensionEncoder.php
Expand Up @@ -4,7 +4,9 @@

namespace Intervention\Image\Encoders;

use Error;
use Intervention\Image\Exceptions\EncoderException;
use Intervention\Image\FileExtension;
use Intervention\Image\Interfaces\EncodedImageInterface;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface;
Expand All @@ -16,10 +18,10 @@ class FileExtensionEncoder extends AutoEncoder
/**
* Create new encoder instance to encode to format of given file extension
*
* @param null|string $extension Target file extension for example "png"
* @param null|string|FileExtension $extension Target file extension for example "png"
* @return void
*/
public function __construct(public ?string $extension = null, mixed ...$options)
public function __construct(public null|string|FileExtension $extension = null, mixed ...$options)
{
$this->options = $options;
}
Expand All @@ -31,37 +33,34 @@ public function __construct(public ?string $extension = null, mixed ...$options)
*/
public function encode(ImageInterface $image): EncodedImageInterface
{
$extension = is_null($this->extension) ? $image->origin()->fileExtension() : $this->extension;

return $image->encode(
$this->encoderByFileExtension(
is_null($this->extension) ? $image->origin()->fileExtension() : $this->extension
$extension
)
);
}

/**
* Create matching encoder for given file extension
*
* @param string $extension
* @param null|string|FileExtension $extension
* @throws EncoderException
* @return EncoderInterface
*/
protected function encoderByFileExtension(?string $extension): EncoderInterface
protected function encoderByFileExtension(null|string|FileExtension $extension): EncoderInterface
{
if (empty($extension)) {
throw new EncoderException('No encoder found for empty file extension.');
}

return match (strtolower($extension)) {
'webp' => new WebpEncoder(...$this->options),
'avif' => new AvifEncoder(...$this->options),
'jpeg', 'jpg' => new JpegEncoder(...$this->options),
'bmp' => new BmpEncoder(...$this->options),
'gif' => new GifEncoder(...$this->options),
'png' => new PngEncoder(...$this->options),
'tiff', 'tif' => new TiffEncoder(...$this->options),
'jp2', 'j2k', 'jpf', 'jpm', 'jpg2', 'j2c', 'jpc', 'jpx' => new Jpeg2000Encoder(...$this->options),
'heic', 'heif' => new HeicEncoder(...$this->options),
default => throw new EncoderException('No encoder found for file extension (' . $extension . ').'),
};
try {
$extension = is_string($extension) ? FileExtension::from($extension) : $extension;
} catch (Error) {
throw new EncoderException('No encoder found for file extension (' . $extension . ').');
}

return $extension->format()->encoder(...$this->options);
}
}
44 changes: 13 additions & 31 deletions src/Encoders/MediaTypeEncoder.php
Expand Up @@ -4,11 +4,13 @@

namespace Intervention\Image\Encoders;

use Error;
use Intervention\Image\Drivers\AbstractEncoder;
use Intervention\Image\Exceptions\EncoderException;
use Intervention\Image\Interfaces\EncodedImageInterface;
use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\MediaType;

class MediaTypeEncoder extends AbstractEncoder
{
Expand All @@ -17,10 +19,10 @@ class MediaTypeEncoder extends AbstractEncoder
/**
* Create new encoder instance
*
* @param null|string $mediaType Target media type for example "image/jpeg"
* @param null|string|MediaType $mediaType Target media type for example "image/jpeg"
* @return void
*/
public function __construct(public ?string $mediaType = null, mixed ...$options)
public function __construct(public null|string|MediaType $mediaType = null, mixed ...$options)
{
$this->options = $options;
}
Expand All @@ -42,38 +44,18 @@ public function encode(ImageInterface $image): EncodedImageInterface
/**
* Return new encoder by given media (MIME) type
*
* @param string $mediaType
* @param string|MediaType $mediaType
* @throws EncoderException
* @return EncoderInterface
*/
protected function encoderByMediaType(string $mediaType): EncoderInterface
protected function encoderByMediaType(string|MediaType $mediaType): EncoderInterface
{
return match (strtolower($mediaType)) {
'image/webp',
'image/x-webp' => new WebpEncoder(...$this->options),
'image/avif',
'image/x-avif' => new AvifEncoder(...$this->options),
'image/jpeg',
'image/jpg',
'image/pjpeg' => new JpegEncoder(...$this->options),
'image/bmp',
'image/ms-bmp',
'image/x-bitmap',
'image/x-bmp',
'image/x-ms-bmp',
'image/x-win-bitmap',
'image/x-windows-bmp',
'image/x-xbitmap' => new BmpEncoder(...$this->options),
'image/gif' => new GifEncoder(...$this->options),
'image/png',
'image/x-png' => new PngEncoder(...$this->options),
'image/tiff' => new TiffEncoder(...$this->options),
'image/jp2',
'image/jpx',
'image/jpm' => new Jpeg2000Encoder(...$this->options),
'image/heic',
'image/heif', => new HeicEncoder(...$this->options),
default => throw new EncoderException('No encoder found for media type (' . $mediaType . ').'),
};
try {
$mediaType = is_string($mediaType) ? MediaType::from($mediaType) : $mediaType;
} catch (Error) {
throw new EncoderException('No encoder found for media type (' . $mediaType . ').');
}

return $mediaType->format()->encoder(...$this->options);
}
}
58 changes: 58 additions & 0 deletions src/FileExtension.php
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Intervention\Image;

enum FileExtension: string
{
case JPG = 'jpg';
case JPEG = 'jpeg';
case WEBP = 'webp';
case AVIF = 'avif';
case BMP = 'bmp';
case GIF = 'gif';
case PNG = 'png';
case TIF = 'tif';
case TIFF = 'tiff';
case JP2 = 'jp2';
case J2K = 'j2k';
case JPF = 'jpf';
case JPM = 'jpm';
case JPG2 = 'jpg2';
case J2C = 'j2c';
case JPC = 'jpc';
case JPX = 'jpx';
case HEIC = 'heic';
case HEIF = 'heif';

/**
* Return the matching format for the current file extension
*
* @return Format
*/
public function format(): Format
{
return match ($this) {
self::JPEG,
self::JPG => Format::JPEG,
self::WEBP => Format::WEBP,
self::GIF => Format::GIF,
self::PNG => Format::PNG,
self::AVIF => Format::AVIF,
self::BMP => Format::BMP,
self::TIF,
self::TIFF => Format::TIFF,
self::JP2,
self::J2K,
self::JPF,
self::JPM,
self::JPG2,
self::J2C,
self::JPC,
self::JPX => Format::JP2,
self::HEIC,
self::HEIF => Format::HEIC,
};
}
}

0 comments on commit 8f6aabe

Please sign in to comment.