diff --git a/CHANGELOG.md b/CHANGELOG.md index 52a53248..717b2e5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,8 @@ ## 1.4.11 -- Updated Blackfire to version 1.92.28. - -## 1.4.11 - - Updated Blackfire to version 1.92.29. +- Upgrade Imagick to version 7.1.1-38 and build with support for AVIF format (aom encoder). ## 1.4.10 diff --git a/layers/imagick/.gitignore b/layers/imagick/.gitignore new file mode 100644 index 00000000..574e3bdc --- /dev/null +++ b/layers/imagick/.gitignore @@ -0,0 +1 @@ +testoutput \ No newline at end of file diff --git a/layers/imagick/Dockerfile b/layers/imagick/Dockerfile index 7f4f657d..0046ee17 100644 --- a/layers/imagick/Dockerfile +++ b/layers/imagick/Dockerfile @@ -3,68 +3,67 @@ ARG BREF_VERSION FROM bref/build-php-$PHP_VERSION:$BREF_VERSION AS ext ARG PHP_VERSION +ENV IMAGICK_VERSION="7.1.1-38" +ENV AOM_VERSION="3.10.0" +ENV LIBHEIF_VERSION="1.19.3" +ENV LIBDE265_VERSION="1.0.15" +ENV LIBWEBP_VERSION="1.4.0" +ENV GS_VERSION="9.56.1" +ENV IMAGICK_EXT_COMMIT="28f27044e435a2b203e32675e942eb8de620ee58" + # Prepare environment ENV IMAGICK_BUILD_DIR=${BUILD_DIR}/imagick RUN mkdir -p ${IMAGICK_BUILD_DIR} -RUN LD_LIBRARY_PATH= yum -y install libpng-devel libjpeg-devel lcms2-devel ImageMagick-devel +WORKDIR ${IMAGICK_BUILD_DIR} +RUN LD_LIBRARY_PATH= yum -y install libpng-devel libjpeg-devel lcms2-devel ImageMagick-devel nasm gcc10 gcc10-c++ + +# Use gcc10 as the default compiler, needed for AOM +ENV CXX="/usr/bin/gcc10-g++" +ENV CC="/usr/bin/gcc10-gcc" # Compile libwebp since AL2 ships with v0.3, and v0.4 or higher is required to builder the other libs -WORKDIR ${IMAGICK_BUILD_DIR} -RUN curl -Ls -o libwebp.tar.gz https://github.com/webmproject/libwebp/archive/refs/tags/v1.4.0.tar.gz -RUN tar xzf libwebp.tar.gz -WORKDIR ${IMAGICK_BUILD_DIR}/libwebp-1.4.0 -RUN autoreconf -i && automake && autoconf -RUN ./configure --prefix ${INSTALL_DIR} --exec-prefix ${INSTALL_DIR} -RUN make -j $(nproc) && make install +RUN curl -Ls -o libwebp.tar.gz https://github.com/webmproject/libwebp/archive/refs/tags/v${LIBWEBP_VERSION}.tar.gz && tar xzf libwebp.tar.gz && rm libwebp.tar.gz \ + && cd ${IMAGICK_BUILD_DIR}/libwebp-${LIBWEBP_VERSION} \ + && autoreconf -i && automake && autoconf \ + && ./configure --prefix ${INSTALL_DIR} --exec-prefix ${INSTALL_DIR} \ + && make -j $(nproc) && make install && rm -rf ${IMAGICK_BUILD_DIR}/libwebp-${LIBWEBP_VERSION} + +# Compile AOM (libavif dependency for AVIF support) +RUN git clone -b v${AOM_VERSION} --depth 1 https://aomedia.googlesource.com/aom \ + && mkdir -p ${IMAGICK_BUILD_DIR}/aom_build && cd ${IMAGICK_BUILD_DIR}/aom_build \ + && cmake ../aom -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} -DBUILD_SHARED_LIBS=1 -DENABLE_DOCS=0 -DENABLE_EXAMPLES=0 -DENABLE_TESTDATA=0 -DENABLE_TESTS=0 -DENABLE_TOOLS=0 \ + && make -j $(nproc) && make install && rm -rf ${IMAGICK_BUILD_DIR}/aom && rm -rf ${IMAGICK_BUILD_DIR}/aom_build # Compile libde265 (libheif dependency) -WORKDIR ${IMAGICK_BUILD_DIR} -RUN curl -Ls -o libde265.tar.gz https://github.com/strukturag/libde265/releases/download/v1.0.15/libde265-1.0.15.tar.gz && tar xzf libde265.tar.gz -WORKDIR ${IMAGICK_BUILD_DIR}/libde265-1.0.15 -RUN ./configure --prefix ${INSTALL_DIR} --exec-prefix ${INSTALL_DIR} -RUN make -j $(nproc) && make install +RUN curl -Ls -o libde265.tar.gz https://github.com/strukturag/libde265/releases/download/v${LIBDE265_VERSION}/libde265-${LIBDE265_VERSION}.tar.gz && tar xzf libde265.tar.gz && rm libde265.tar.gz \ + && cd ${IMAGICK_BUILD_DIR}/libde265-${LIBDE265_VERSION} \ + && ./configure --prefix ${INSTALL_DIR} --exec-prefix ${INSTALL_DIR} \ + && make -j $(nproc) && make install && rm -rf ${IMAGICK_BUILD_DIR}/libde265-${LIBDE265_VERSION} # Compile libheif -WORKDIR ${IMAGICK_BUILD_DIR} -RUN curl -Ls -o libheif.tar.gz https://github.com/strukturag/libheif/releases/download/v1.13.0/libheif-1.13.0.tar.gz && tar xzf libheif.tar.gz -WORKDIR ${IMAGICK_BUILD_DIR}/libheif-1.13.0 -RUN ./configure --prefix ${INSTALL_DIR} --exec-prefix ${INSTALL_DIR} -RUN make -j $(nproc) && make install +RUN curl -Ls -o libheif.tar.gz https://github.com/strukturag/libheif/releases/download/v${LIBHEIF_VERSION}/libheif-${LIBHEIF_VERSION}.tar.gz \ + && tar xzf libheif.tar.gz && rm libheif.tar.gz && mkdir -p ${IMAGICK_BUILD_DIR}/libheif-${LIBHEIF_VERSION}/build && cd ${IMAGICK_BUILD_DIR}/libheif-${LIBHEIF_VERSION}/build \ + && cmake --preset=release-noplugins .. -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} \ + && make -j $(nproc) && make install && rm -rf ${IMAGICK_BUILD_DIR}/libheif-${LIBHEIF_VERSION} # Compile gs -WORKDIR ${IMAGICK_BUILD_DIR} -RUN curl -Ls -o ghostscript.tar.gz https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs9561/ghostscript-9.56.1.tar.gz && tar xzf ghostscript.tar.gz -WORKDIR ${IMAGICK_BUILD_DIR}/ghostscript-9.56.1 -RUN ./configure --prefix ${INSTALL_DIR} --exec-prefix ${INSTALL_DIR} --without-x -RUN make -j $(nproc) && cp bin/gs /tmp/gs +RUN curl -Ls -o ghostscript.tar.gz https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs9561/ghostscript-${GS_VERSION}.tar.gz && tar xzf ghostscript.tar.gz && rm ghostscript.tar.gz \ + && mkdir -p ${IMAGICK_BUILD_DIR}/ghostscript-${GS_VERSION} && cd ${IMAGICK_BUILD_DIR}/ghostscript-${GS_VERSION} \ + && ./configure --prefix ${INSTALL_DIR} --exec-prefix ${INSTALL_DIR} --without-x \ + && make -j $(nproc) && cp bin/gs /tmp/gs && rm -rf ${IMAGICK_BUILD_DIR}/ghostscript-${GS_VERSION} # Compile the ImageMagick library -WORKDIR ${IMAGICK_BUILD_DIR} -RUN curl -Ls -o ImageMagick.tar.gz https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.1-38.tar.gz && tar xzf ImageMagick.tar.gz -WORKDIR ${IMAGICK_BUILD_DIR}/ImageMagick-7.1.1-38 -RUN ./configure --prefix ${INSTALL_DIR} --exec-prefix ${INSTALL_DIR} --with-webp --with-heic --disable-static --with-freetype=yes -RUN make -j $(nproc) -RUN make install - -# Show how ImageMagick is configured. See the "delicate" section -RUN convert -list configure - -# Compile the php imagick extension -WORKDIR ${IMAGICK_BUILD_DIR} -RUN git clone https://github.com/Imagick/imagick -WORKDIR ${IMAGICK_BUILD_DIR}/imagick -# TODO; update the commit hash when there's a new release -RUN git reset --hard 28f27044e435a2b203e32675e942eb8de620ee58 -RUN phpize -RUN ./configure --with-imagick=${INSTALL_DIR} -RUN make -j $(nproc) -RUN make install - -RUN cp `php-config --extension-dir`/imagick.so /tmp/imagick.so -RUN strip --strip-debug /tmp/imagick.so -RUN echo 'extension=imagick.so' > /tmp/ext.ini +RUN curl -Ls -o ImageMagick.tar.gz https://github.com/ImageMagick/ImageMagick/archive/refs/tags/${IMAGICK_VERSION}.tar.gz && tar xzf ImageMagick.tar.gz && rm ImageMagick.tar.gz \ + && cd ${IMAGICK_BUILD_DIR}/ImageMagick-${IMAGICK_VERSION} \ + && ./configure --prefix ${INSTALL_DIR} --exec-prefix ${INSTALL_DIR} --with-webp --with-heic --disable-static --with-freetype=yes \ + && make -j $(nproc) && make install && rm -rf ${IMAGICK_BUILD_DIR}/ImageMagick-${IMAGICK_VERSION} && convert -list configure -RUN php /bref/lib-copy/copy-dependencies.php /tmp/imagick.so /tmp/extension-libs +# Compile the php imagick extension and copy the dependencies +RUN git clone https://github.com/Imagick/imagick && cd imagick \ + &&git reset --hard ${IMAGICK_EXT_COMMIT} \ + && phpize && ./configure --with-imagick=${INSTALL_DIR} \ + && make -j $(nproc) && make install && cp `php-config --extension-dir`/imagick.so /tmp/imagick.so && strip --strip-debug /tmp/imagick.so && echo 'extension=imagick.so' > /tmp/ext.ini \ + && php /bref/lib-copy/copy-dependencies.php /tmp/imagick.so /tmp/extension-libs # Build the final image with just the files we need FROM scratch diff --git a/layers/imagick/test.php b/layers/imagick/test.php index 42889618..91a0e821 100644 --- a/layers/imagick/test.php +++ b/layers/imagick/test.php @@ -5,7 +5,9 @@ exit(1); } -foreach (['PNG', 'JPG', 'GIF', 'WEBP', 'HEIC'] as $format) { +$expected_formats = ['PNG', 'JPG', 'GIF', 'WEBP', 'HEIC', 'AVIF']; + +foreach ( $expected_formats as $format) { if (!\Imagick::queryFormats($format)) { echo sprintf('FAIL: Imagick does not support "%s".', $format).PHP_EOL; exit(1); @@ -27,16 +29,48 @@ exit(1); } + try { - $image = new \Imagick(__DIR__.'/test.pdf'); - $image->writeImage('/tmp/imagick-test.jpg'); - assert(file_exists('/tmp/imagick-test.jpg')); + $tmpdir = '/tmp/imagicktest'; + mkdir($tmpdir); + + foreach ($expected_formats as $format) { + //for all files in the testfiles directory + foreach (glob(__DIR__.'/testfiles/*') as $file) { + $image = new \Imagick($file); + $output_path = $tmpdir . '/' .pathinfo($file, PATHINFO_FILENAME) . '.' . strtolower($format); + $image->writeImage($output_path); + validateImageFile($output_path); + } + } + + // compare the size of the AVIF image with the original JPG, buggy builds may just copy the jpg + assert(filesize( $tmpdir . '/jpg_test.avif') < filesize(__DIR__.'/testfiles/jpg_test.jpg') * 0.9); + + // copy the output files to the testoutput directory, if it exists. Useful for local testing + if (file_exists('/var/task/testoutput')){ + foreach (glob($tmpdir.'/*') as $file) { + copy($file, '/var/task/testoutput/'.basename($file)); + } + } + } catch(\ImagickException $e) { - echo sprintf('FAIL: Imagick cannot convert PDF "%s".', $e->getMessage()).PHP_EOL; + echo sprintf('FAIL: Imagick failed to write image "%s".', $e->getMessage()).PHP_EOL; exit(1); } catch (\Throwable $e) { echo sprintf('FAIL: Imagick failed with "%s" exception: %s', get_class($e), $e->getMessage()).PHP_EOL; exit(1); } +// some basic image validation +function validateImageFile($file) { + assert(file_exists($file), 'File does not exist: ' . $file); + assert(filesize($file) > 128, 'File size ( '. filesize($file) .' byte ) is < byte for ' . $file ); + // only for supported formats + if (in_array(pathinfo($file, PATHINFO_EXTENSION), ['png', 'jpg', 'webp', 'avif']) && version_compare(phpversion(), '8.3', '>=')) { + assert(getimagesize($file) !== false, 'getimagesize failed for ' . $file); + } + +} + exit(0); diff --git a/layers/imagick/testfiles/avif_test.avif b/layers/imagick/testfiles/avif_test.avif new file mode 100644 index 00000000..f9247c91 Binary files /dev/null and b/layers/imagick/testfiles/avif_test.avif differ diff --git a/layers/imagick/testfiles/jpg_test.jpg b/layers/imagick/testfiles/jpg_test.jpg new file mode 100644 index 00000000..d05f9d62 Binary files /dev/null and b/layers/imagick/testfiles/jpg_test.jpg differ diff --git a/layers/imagick/test.pdf b/layers/imagick/testfiles/pdf_test.pdf similarity index 100% rename from layers/imagick/test.pdf rename to layers/imagick/testfiles/pdf_test.pdf diff --git a/layers/imagick/testfiles/png_test.png b/layers/imagick/testfiles/png_test.png new file mode 100644 index 00000000..c40ae0c7 Binary files /dev/null and b/layers/imagick/testfiles/png_test.png differ