From 6bad6ec08faa0cbe3e52b0b275427d775bc07120 Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Wed, 29 Sep 2021 09:31:34 +0200 Subject: [PATCH] Enable AVIF for GD on PHP 8.1 (#375) --- README.md | 1 + install-php-extensions | 157 ++++++++++++++++++++++++++++++++++++++++- scripts/tests/gd | 21 ++++-- 3 files changed, 172 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7093c98..36fb93b 100644 --- a/README.md +++ b/README.md @@ -301,6 +301,7 @@ Here's the list of all the supported environment variables: | | `IPE_KEEP_SYSPKG_CACHE=1` | By default the script will clear the apt/apk/pear cache in order to save disk space. You can disable it by setting this environment variable | | lzf | `IPE_LZF_BETTERCOMPRESSION=1` | By default `install-php-extensions` compiles the `lzf` extension to prefer speed over size; you can use this environment variable to compile it preferring size over speed | | event | `IPE_EVENT_NAMESPACE=`... | By default the `event` classes are defined in the root namespace. You can use this environment variable to specify a custom namespace | +| gd | IPE_GD_WITHOUTAVIF=1 | Since PHP 8.1, gd supports the AVIF format. Enabling it requires compiling libaom/libdav1d/libyuv/libavif, which is time-consuming. You can disable AVIF support by setting this environment variable | ## Special requirements diff --git a/install-php-extensions b/install-php-extensions index 90a3640..36f1e89 100755 --- a/install-php-extensions +++ b/install-php-extensions @@ -553,6 +553,19 @@ buildRequiredPackageLists() { else buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libwebp" buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libwebp-dev" + if test $PHP_MAJMIN_VERSION -ge 801; then + if isLibaomInstalled && isLibdav1dInstalled && isLibyuvInstalled && isLibavifInstalled; then + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libstdc++" + else + case "${IPE_GD_WITHOUTAVIF:-}" in + 1 | y* | Y*) ;; + *) + buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent libstdc++" + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile cmake nasm meson" + ;; + esac + fi + fi fi ;; gd@debian) @@ -564,6 +577,16 @@ buildRequiredPackageLists() { else buildRequiredPackageLists_persistent="$buildRequiredPackageLists_persistent ^libwebp[0-9]+$" buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile libwebp-dev" + if test $PHP_MAJMIN_VERSION -ge 801; then + if ! isLibaomInstalled || ! isLibdav1dInstalled || ! isLibyuvInstalled || ! isLibavifInstalled; then + case "${IPE_GD_WITHOUTAVIF:-}" in + 1 | y* | Y*) ;; + *) + buildRequiredPackageLists_volatile="$buildRequiredPackageLists_volatile cmake nasm meson" + ;; + esac + fi + fi fi ;; gearman@alpine) @@ -1418,6 +1441,115 @@ installMicrosoftSqlServerODBC() { esac } +# Check if libaom is installed +# +# Return: +# 0 (true) +# 1 (false) +isLibaomInstalled() { + if ! test -f /usr/local/lib/libaom.so && ! test -f /usr/lib/libaom.so; then + return 1 + fi + if ! test -f /usr/local/include/aom/aom_codec.h && ! test -f /usr/include/aom/aom_codec.h; then + return 1 + fi + return 0 +} + +# Install libaom +installLibaom() { + printf 'Installing libaom\n' + installLibaom_dir="$(getPackageSource https://aomedia.googlesource.com/aom/+archive/v3.1.2.tar.gz)" + mkdir -- "$installLibaom_dir/my.build" + cd -- "$installLibaom_dir/my.build" + cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 -DENABLE_DOCS=0 -DENABLE_EXAMPLES=0 -DENABLE_TESTDATA=0 -DENABLE_TESTS=0 -DENABLE_TOOLS=0 -DCMAKE_INSTALL_LIBDIR:PATH=lib .. + ninja -j $(getProcessorCount) install + cd - >/dev/null + ldconfig || true +} + +# Check if libdav1d is installed +# +# Return: +# 0 (true) +# 1 (false) +isLibdav1dInstalled() { + if ! test -f /usr/local/lib/libdav1d.so && ! test -f /usr/lib/libdav1d.so; then + return 1 + fi + if ! test -f /usr/local/include/dav1d/dav1d.h && ! test -f /usr/include/dav1d/dav1d.h; then + return 1 + fi + return 0 +} + +# Install libdav1d +installLibdav1d() { + printf 'Installing libdav1d\n' + installLibdav1d_dir="$(getPackageSource https://code.videolan.org/videolan/dav1d/-/archive/0.9.2/dav1d-0.9.2.tar.gz)" + mkdir -- "$installLibdav1d_dir/build" + cd -- "$installLibdav1d_dir/build" + meson --buildtype release -Dprefix=/usr .. + ninja -j $(getProcessorCount) install + cd - >/dev/null + if test -f /usr/lib/$TARGET_TRIPLET/libdav1d.so && ! test -f /usr/lib/libdav1d.so; then + ln -s /usr/lib/$TARGET_TRIPLET/libdav1d.so /usr/lib/ + fi + ldconfig || true +} + +# Check if libyuv is installed +# +# Return: +# 0 (true) +# 1 (false) +isLibyuvInstalled() { + if ! test -f /usr/local/lib/libyuv.so && ! test -f /usr/lib/libyuv.so; then + return 1 + fi + if ! test -f /usr/local/include/libyuv.h && ! test -f /usr/include/libyuv.h; then + return 1 + fi + return 0 +} + +# Install libyuv +installLibyuv() { + printf 'Installing libyuv\n' + installLibyuv_dir="$(getPackageSource https://chromium.googlesource.com/libyuv/libyuv/+archive/refs/heads/main.tar.gz)" + mkdir -- "$installLibyuv_dir/build" + cd -- "$installLibyuv_dir/build" + cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -B. .. + make -j$(getProcessorCount) install + cd - >/dev/null +} + +# Check if libavif is installed +# +# Return: +# 0 (true) +# 1 (false) +isLibavifInstalled() { + if ! test -f /usr/local/lib/libavif.so && ! test -f /usr/lib/libavif.so; then + return 1 + fi + if ! test -f /usr/local/include/avif/avif.h && ! test -f /usr/include/avif/avif.h; then + return 1 + fi + return 0 +} + +# Install libavif +installLibavif() { + printf 'Installing libavif\n' + installLibavif_dir="$(getPackageSource https://codeload.github.com/AOMediaCodec/libavif/tar.gz/refs/tags/v0.9.2)" + mkdir -- "$installLibavif_dir/build" + cd -- "$installLibavif_dir/build" + cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DAVIF_CODEC_AOM=ON -DCMAKE_INSTALL_LIBDIR:PATH=lib + make -j$(getProcessorCount) install + cd - >/dev/null +} + # Install Composer installComposer() { installComposer_version="$(getWantedPHPModuleVersion @composer)" @@ -1603,8 +1735,31 @@ EOF docker-php-ext-configure gd --with-gd --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir --enable-gd-native-ttf --with-webp-dir elif test $PHP_MAJMIN_VERSION -le 703; then docker-php-ext-configure gd --with-gd --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir --with-webp-dir - else + elif test $PHP_MAJMIN_VERSION -le 800; then docker-php-ext-configure gd --enable-gd --with-webp --with-jpeg --with-xpm --with-freetype + else + case "${IPE_GD_WITHOUTAVIF:-}" in + 1 | y* | Y*) ;; + *) + if ! isLibaomInstalled; then + installLibaom + fi + if ! isLibdav1dInstalled; then + installLibdav1d + fi + if ! isLibyuvInstalled; then + installLibyuv + fi + if ! isLibavifInstalled; then + installLibavif + fi + ;; + esac + if isLibaomInstalled && isLibdav1dInstalled && isLibyuvInstalled && isLibavifInstalled; then + docker-php-ext-configure gd --enable-gd --with-webp --with-jpeg --with-xpm --with-freetype --with-avif + else + docker-php-ext-configure gd --enable-gd --with-webp --with-jpeg --with-xpm --with-freetype + fi fi ;; gmp) diff --git a/scripts/tests/gd b/scripts/tests/gd index c494500..a462e9d 100755 --- a/scripts/tests/gd +++ b/scripts/tests/gd @@ -3,9 +3,12 @@ require_once __DIR__ . '/_bootstrap.php'; +echo 'Creating sample image... '; $imageWidth = 8; $imageHeight = 16; $image = imagecreatetruecolor($imageWidth, $imageHeight); +echo "done.\n"; + $formats = [ 'gd2', 'gif', @@ -19,24 +22,29 @@ $formats = [ 'gd', ]; if (PHP_VERSION_ID >= 70200) { - $formats = array_merge($formats, [ - 'bmp', - ]); + $formats[] = 'bmp'; + if (PHP_VERSION_ID >= 80100) { + $formats[] = 'avif'; + } } $tempFile = null; $image2 = null; try { foreach ($formats as $format) { + echo "Checking format {$format}... "; $loadFuntion = "imagecreatefrom{$format}"; if (!function_exists($loadFuntion)) { throw new Exception("{$loadFuntion}() function is missing"); } - if ($format === 'xpm') { - continue; - } $saveFuntion = "image{$format}"; if (!function_exists($saveFuntion)) { + if ($format === 'xpm') { + echo "skipping tests since PHP can't save images to that format.\n"; + + continue; + } + throw new Exception("{$saveFuntion}() function is missing"); } $tempFile = tempnam(sys_get_temp_dir(), 'dpei'); @@ -62,6 +70,7 @@ try { throw new Exception("{$loadFuntion}() failed"); } imagedestroy($image2); + echo "done.\n"; } if (!function_exists('imagefttext')) { throw new Exception('imagefttext() function is missing');