Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imagick: build with support for AVIF format by aom encoder #566

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change log

## 1.4.11

- Upgrade Imagick to version 7.1.1-38 and build with support for AVIF format (aom encoder).

## 1.4.10

- Updated Blackfire to version 1.92.26.
Expand Down
1 change: 1 addition & 0 deletions layers/imagick/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
testoutput
95 changes: 47 additions & 48 deletions layers/imagick/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
44 changes: 39 additions & 5 deletions layers/imagick/test.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Binary file added layers/imagick/testfiles/avif_test.avif
Binary file not shown.
Binary file added layers/imagick/testfiles/jpg_test.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
Binary file added layers/imagick/testfiles/png_test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading