Skip to content

Commit ab01d5e

Browse files
authored
feat: AVIF image support (#10025)
1 parent 97c0a83 commit ab01d5e

File tree

14 files changed

+146
-26
lines changed

14 files changed

+146
-26
lines changed

.github/workflows/reusable-phpunit-test.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,16 @@ jobs:
168168
if: ${{ contains(inputs.extra-extensions, 'imagick') }}
169169
run: |
170170
sudo apt-get update
171-
sudo apt-get install -y imagemagick libmagickwand-dev ghostscript poppler-data libjbig2dec0:amd64 libopenjp2-7:amd64
171+
sudo apt-get install -y ghostscript poppler-data libmagickwand-dev
172+
173+
# Install ImageMagick 7 with AVIF rw+ support (vintagesucks/imagemagick-deb)
174+
RELEASE_JSON=$(curl -fsSL https://api.github.com/repos/vintagesucks/imagemagick-deb/releases/latest)
175+
mkdir -p /tmp/imagemagick-debs
176+
while IFS= read -r url; do
177+
curl -fsSL "$url" -o "/tmp/imagemagick-debs/$(basename "$url")"
178+
done < <(echo "$RELEASE_JSON" | jq -r '.assets[] | select(.name | contains("noble_amd64")) | .browser_download_url')
179+
sudo dpkg -i /tmp/imagemagick-debs/*.deb || true
180+
sudo apt-get install -f -y
172181
173182
- name: Checkout base branch for PR
174183
if: github.event_name == 'pull_request'

app/Config/Mimes.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ class Mimes
259259
'image/x-png',
260260
],
261261
'webp' => 'image/webp',
262+
'avif' => 'image/avif',
262263
'tif' => 'image/tiff',
263264
'tiff' => 'image/tiff',
264265
'css' => [

app/Config/Publisher.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ class Publisher extends BasePublisher
2323
*/
2424
public $restrictions = [
2525
ROOTPATH => '*',
26-
FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i',
26+
FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|avif|bmp|ico|svg)$#i',
2727
];
2828
}

system/Config/Publisher.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Publisher extends BaseConfig
3232
*/
3333
public $restrictions = [
3434
ROOTPATH => '*',
35-
FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i',
35+
FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|avif|bmp|ico|svg)$#i',
3636
];
3737

3838
/**

system/Images/Handlers/BaseHandler.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ abstract class BaseHandler implements ImageHandlerInterface
115115
protected $supportTransparency = [
116116
IMAGETYPE_PNG,
117117
IMAGETYPE_WEBP,
118+
IMAGETYPE_AVIF,
118119
];
119120

120121
/**

system/Images/Handlers/GDHandler.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ protected function process(string $action)
178178

179179
$dest = $create($this->width, $this->height);
180180

181-
// for png and webp we can actually preserve transparency
181+
// for png, webp and avif we can actually preserve transparency
182182
if (in_array($this->image()->imageType, $this->supportTransparency, true)) {
183183
imagealphablending($dest, false);
184184
imagesavealpha($dest, true);
@@ -222,7 +222,7 @@ public function save(?string $target = null, int $quality = 90): bool
222222

223223
$this->ensureResource();
224224

225-
// for png and webp we can actually preserve transparency
225+
// for png, webp and avif we can actually preserve transparency
226226
if (in_array($this->image()->imageType, $this->supportTransparency, true)) {
227227
imagepalettetotruecolor($this->resource);
228228
imagealphablending($this->resource, false);
@@ -270,6 +270,16 @@ public function save(?string $target = null, int $quality = 90): bool
270270
}
271271
break;
272272

273+
case IMAGETYPE_AVIF:
274+
if (! function_exists('imageavif')) {
275+
throw ImageException::forInvalidImageCreate(lang('Images.avifNotSupported'));
276+
}
277+
278+
if (! @imageavif($this->resource, $target, $quality)) {
279+
throw ImageException::forSaveFailed();
280+
}
281+
break;
282+
273283
default:
274284
throw ImageException::forInvalidImageCreate();
275285
}
@@ -361,6 +371,13 @@ protected function getImageResource(string $path, int $imageType)
361371

362372
return imagecreatefromwebp($path);
363373

374+
case IMAGETYPE_AVIF:
375+
if (! function_exists('imagecreatefromavif')) {
376+
throw ImageException::forInvalidImageCreate(lang('Images.avifNotSupported'));
377+
}
378+
379+
return imagecreatefromavif($path);
380+
364381
default:
365382
throw ImageException::forInvalidImageCreate('Ima');
366383
}

system/Images/Handlers/ImageMagickHandler.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,38 @@ protected function supportedFormatCheck()
306306
return;
307307
}
308308

309-
if ($this->image()->imageType === IMAGETYPE_WEBP && ! in_array('WEBP', Imagick::queryFormats(), true)) {
310-
throw ImageException::forInvalidImageCreate(lang('images.webpNotSupported'));
309+
$supported = Imagick::queryFormats();
310+
311+
switch ($this->image()->imageType) {
312+
case IMAGETYPE_GIF:
313+
if (! in_array('GIF', $supported, true)) {
314+
throw ImageException::forInvalidImageCreate(lang('Images.gifNotSupported'));
315+
}
316+
break;
317+
318+
case IMAGETYPE_JPEG:
319+
if (! in_array('JPEG', $supported, true)) {
320+
throw ImageException::forInvalidImageCreate(lang('Images.jpgNotSupported'));
321+
}
322+
break;
323+
324+
case IMAGETYPE_PNG:
325+
if (! in_array('PNG', $supported, true)) {
326+
throw ImageException::forInvalidImageCreate(lang('Images.pngNotSupported'));
327+
}
328+
break;
329+
330+
case IMAGETYPE_WEBP:
331+
if (! in_array('WEBP', $supported, true)) {
332+
throw ImageException::forInvalidImageCreate(lang('Images.webpNotSupported'));
333+
}
334+
break;
335+
336+
case IMAGETYPE_AVIF:
337+
if (! in_array('AVIF', $supported, true)) {
338+
throw ImageException::forInvalidImageCreate(lang('Images.avifNotSupported'));
339+
}
340+
break;
311341
}
312342
}
313343

system/Images/Image.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ public function getProperties(bool $return = false)
113113
IMAGETYPE_JPEG => 'jpeg',
114114
IMAGETYPE_PNG => 'png',
115115
IMAGETYPE_WEBP => 'webp',
116+
IMAGETYPE_AVIF => 'avif',
116117
];
117118

118119
$mime = 'image/' . ($types[$vals[2]] ?? 'jpg');

system/Language/en/Images.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
'jpgNotSupported' => 'JPG images are not supported.',
2121
'pngNotSupported' => 'PNG images are not supported.',
2222
'webpNotSupported' => 'WEBP images are not supported.',
23+
'avifNotSupported' => 'AVIF images are not supported.',
2324
'fileNotSupported' => 'The supplied file is not a supported image type.',
2425
'unsupportedImageCreate' => 'Your server does not support the required functionality to process this type of image.',
2526
'jpgOrPngRequired' => 'The image resize protocol specified in your preferences only works with JPEG or PNG image types.',

tests/_support/Images/ci-logo.avif

2.29 KB
Binary file not shown.

0 commit comments

Comments
 (0)