diff --git a/src/Drivers/Gd/Decoders/FilePathImageDecoder.php b/src/Drivers/Gd/Decoders/FilePathImageDecoder.php index ae04d1ff..21ed1c70 100644 --- a/src/Drivers/Gd/Decoders/FilePathImageDecoder.php +++ b/src/Drivers/Gd/Decoders/FilePathImageDecoder.php @@ -24,9 +24,11 @@ public function decode(mixed $input): ImageInterface|ColorInterface throw new DecoderException('Unable to decode input'); } + // decode image $image = parent::decode(file_get_contents($input)); - // set origin + // set file path on origin + $image->origin()->setFilePath($input); return $image; } diff --git a/src/Drivers/Imagick/Decoders/FilePathImageDecoder.php b/src/Drivers/Imagick/Decoders/FilePathImageDecoder.php index ad7b8af8..b5b80f81 100644 --- a/src/Drivers/Imagick/Decoders/FilePathImageDecoder.php +++ b/src/Drivers/Imagick/Decoders/FilePathImageDecoder.php @@ -12,18 +12,24 @@ class FilePathImageDecoder extends BinaryImageDecoder implements DecoderInterfac { public function decode(mixed $input): ImageInterface|ColorInterface { - if (! is_string($input)) { + if (!is_string($input)) { throw new DecoderException('Unable to decode input'); } try { - if (! @is_file($input)) { + if (!@is_file($input)) { throw new DecoderException('Unable to decode input'); } } catch (Exception $e) { throw new DecoderException('Unable to decode input'); } - return parent::decode(file_get_contents($input)); + // decode image + $image = parent::decode(file_get_contents($input)); + + // set file path on origin + $image->origin()->setFilePath($input); + + return $image; } } diff --git a/src/Encoders/AutoEncoder.php b/src/Encoders/AutoEncoder.php index f57ef302..614b2e6a 100644 --- a/src/Encoders/AutoEncoder.php +++ b/src/Encoders/AutoEncoder.php @@ -2,12 +2,10 @@ namespace Intervention\Image\Encoders; -use Intervention\Gif\Exception\EncoderException; use Intervention\Image\Interfaces\EncodedImageInterface; -use Intervention\Image\Interfaces\EncoderInterface; use Intervention\Image\Interfaces\ImageInterface; -class AutoEncoder implements EncoderInterface +class AutoEncoder extends MediaTypeEncoder { /** * {@inheritdoc} @@ -22,25 +20,4 @@ public function encode(ImageInterface $image): EncodedImageInterface ) ); } - - /** - * Return encoder matching to encode given media (mime) type - * - * @param string $type - * @return EncoderInterface - * @throws EncoderException - */ - protected function encoderByMediaType(string $type): EncoderInterface - { - return match ($type) { - 'image/webp' => new WebpEncoder(), - 'image/avif' => new AvifEncoder(), - 'image/jpeg' => new JpegEncoder(), - 'image/bmp' => new BmpEncoder(), - 'image/gif' => new GifEncoder(), - 'image/png' => new PngEncoder(), - 'image/tiff' => new TiffEncoder(), - default => throw new EncoderException('No encoder found for media type (' . $type . ').'), - }; - } } diff --git a/src/Encoders/FileExtensionEncoder.php b/src/Encoders/FileExtensionEncoder.php new file mode 100644 index 00000000..ba318f70 --- /dev/null +++ b/src/Encoders/FileExtensionEncoder.php @@ -0,0 +1,49 @@ +encode( + $this->encoderByFileExtension( + is_null($this->extension) ? $image->origin()->fileExtension() : $this->extension + ) + ); + } + + protected function encoderByFileExtension(string $extension): EncoderInterface + { + return match ($extension) { + 'webp' => new WebpEncoder(), + 'avif' => new AvifEncoder(), + 'jpeg', 'jpg' => new JpegEncoder(), + 'bmp' => new BmpEncoder(), + 'gif' => new GifEncoder(), + 'png' => new PngEncoder(), + 'tiff', 'tif' => new TiffEncoder(), + default => throw new EncoderException('No encoder found for file extension (' . $extension . ').'), + }; + } +} diff --git a/src/Encoders/MediaTypeEncoder.php b/src/Encoders/MediaTypeEncoder.php index 6cd779d2..3a05b0d7 100644 --- a/src/Encoders/MediaTypeEncoder.php +++ b/src/Encoders/MediaTypeEncoder.php @@ -2,10 +2,12 @@ namespace Intervention\Image\Encoders; +use Intervention\Gif\Exception\EncoderException; use Intervention\Image\Interfaces\EncodedImageInterface; +use Intervention\Image\Interfaces\EncoderInterface; use Intervention\Image\Interfaces\ImageInterface; -class MediaTypeEncoder extends AutoEncoder +class MediaTypeEncoder implements EncoderInterface { /** * Create new encoder instance to encode given media (mime) type @@ -24,10 +26,31 @@ public function __construct(protected ?string $type = null) */ public function encode(ImageInterface $image): EncodedImageInterface { + $type = is_null($this->type) ? $image->origin()->mediaType() : $this->type; + return $image->encode( - $this->encoderByMediaType( - is_null($this->type) ? $image->origin()->mediaType() : $this->type - ) + $this->encoderByMediaType($type) ); } + + /** + * Return new encoder by given media (MIME) type + * + * @param string $type + * @return EncoderInterface + * @throws EncoderException + */ + protected function encoderByMediaType(string $type): EncoderInterface + { + return match ($type) { + 'image/webp' => new WebpEncoder(), + 'image/avif' => new AvifEncoder(), + 'image/jpeg' => new JpegEncoder(), + 'image/bmp' => new BmpEncoder(), + 'image/gif' => new GifEncoder(), + 'image/png' => new PngEncoder(), + 'image/tiff' => new TiffEncoder(), + default => throw new EncoderException('No encoder found for media type (' . $type . ').'), + }; + } } diff --git a/src/Image.php b/src/Image.php index 18bd6582..17582130 100644 --- a/src/Image.php +++ b/src/Image.php @@ -14,6 +14,7 @@ use Intervention\Image\Encoders\AutoEncoder; use Intervention\Image\Encoders\AvifEncoder; use Intervention\Image\Encoders\BmpEncoder; +use Intervention\Image\Encoders\FileExtensionEncoder; use Intervention\Image\Encoders\GifEncoder; use Intervention\Image\Encoders\JpegEncoder; use Intervention\Image\Encoders\MediaTypeEncoder; @@ -755,6 +756,16 @@ public function encodeByMediaType(?string $type = null): EncodedImageInterface return $this->encode(new MediaTypeEncoder($type)); } + /** + * {@inheritdoc} + * + * @see ImageInterface::encodeByExtension() + */ + public function encodeByExtension(?string $extension = null): EncodedImageInterface + { + return $this->encode(new FileExtensionEncoder($extension)); + } + /** * {@inheritdoc} * diff --git a/src/Interfaces/ImageInterface.php b/src/Interfaces/ImageInterface.php index 668fd757..285f760e 100644 --- a/src/Interfaces/ImageInterface.php +++ b/src/Interfaces/ImageInterface.php @@ -566,6 +566,16 @@ public function drawLine(callable $init): ImageInterface; */ public function encodeByMediaType(?string $type = null): EncodedImageInterface; + /** + * Encode the image into the format represented by the given extension. If no + * extension is given the image will be encoded to the format of the + * originally read image. + * + * @param null|string $extension + * @return EncodedImageInterface + */ + public function encodeByExtension(?string $extension = null): EncodedImageInterface; + /** * Encode image to JPEG format * diff --git a/src/Origin.php b/src/Origin.php index 1dea1f7e..1a001f39 100644 --- a/src/Origin.php +++ b/src/Origin.php @@ -8,20 +8,53 @@ class Origin * Create new origin instance * * @param string $mediaType + * @param null|string $filePath * @return void */ public function __construct( - protected string $mediaType = 'application/octet-stream' + protected string $mediaType = 'application/octet-stream', + protected ?string $filePath = null ) { } + /** + * Return media type of origin + * + * @return string + */ public function mediaType(): string { return $this->mediaType; } + /** + * Alias of self::mediaType() + */ public function mimetype(): string { return $this->mediaType(); } + + /** + * Set file path for origin + * + * @param string $path + * @return Origin + */ + public function setFilePath(string $path): self + { + $this->filePath = $path; + + return $this; + } + + /** + * Return file extension if origin was created from file path + * + * @return null|string + */ + public function fileExtension(): ?string + { + return empty($this->filePath) ? null : pathinfo($this->filePath, PATHINFO_EXTENSION); + } } diff --git a/tests/Drivers/Gd/ImageTest.php b/tests/Drivers/Gd/ImageTest.php index c49d4b23..f5d1a093 100644 --- a/tests/Drivers/Gd/ImageTest.php +++ b/tests/Drivers/Gd/ImageTest.php @@ -133,6 +133,17 @@ public function testEncodeByMediaType(): void $this->assertMediaType('image/png', (string) $result); } + public function testEncodeByExtension(): void + { + $result = $this->readTestImage('blue.gif')->encodeByExtension(); + $this->assertInstanceOf(EncodedImage::class, $result); + $this->assertMediaType('image/gif', (string) $result); + + $result = $this->readTestImage('blue.gif')->encodeByExtension('png'); + $this->assertInstanceOf(EncodedImage::class, $result); + $this->assertMediaType('image/png', (string) $result); + } + public function testWidthHeightSize(): void { $this->assertEquals(3, $this->image->width()); diff --git a/tests/Drivers/Imagick/ImageTest.php b/tests/Drivers/Imagick/ImageTest.php index 5623d857..dc9116ec 100644 --- a/tests/Drivers/Imagick/ImageTest.php +++ b/tests/Drivers/Imagick/ImageTest.php @@ -132,6 +132,17 @@ public function testEncodeByMediaType(): void $this->assertMediaType('image/png', (string) $result); } + public function testEncodeByExtension(): void + { + $result = $this->readTestImage('blue.gif')->encodeByExtension(); + $this->assertInstanceOf(EncodedImage::class, $result); + $this->assertMediaType('image/gif', (string) $result); + + $result = $this->readTestImage('blue.gif')->encodeByExtension('png'); + $this->assertInstanceOf(EncodedImage::class, $result); + $this->assertMediaType('image/png', (string) $result); + } + public function testWidthHeightSize(): void { $this->assertEquals(20, $this->image->width()); diff --git a/tests/OriginTest.php b/tests/OriginTest.php index 9bbb3066..9d9b2cdc 100644 --- a/tests/OriginTest.php +++ b/tests/OriginTest.php @@ -14,4 +14,13 @@ public function testMediaType(): void $origin = new Origin('image/gif'); $this->assertEquals('image/gif', $origin->mediaType()); } + + public function testFileExtension(): void + { + $origin = new Origin('image/jpeg', __DIR__ . '/tests/images/example.jpg'); + $this->assertEquals('jpg', $origin->fileExtension()); + + $origin = new Origin('image/jpeg'); + $this->assertEquals('', $origin->fileExtension()); + } }