diff --git a/client-examples/1.webp b/client-examples/1.webp new file mode 100644 index 0000000..122741b Binary files /dev/null and b/client-examples/1.webp differ diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index 0b9eb49..fce76d5 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -1,8 +1,37 @@ -FROM rustembedded/cross:x86_64-unknown-linux-gnu AS x86_64-builder +# Target environment +FROM amd64/ubuntu:20.04 as target-env + +ENV \ + TARGET=x86_64-unknown-linux-gnu \ + BUILD_MODE=release + +# Basic cross-build environment +FROM ubuntu:20.04 as cross-build + +ENV \ + ARCH=amd64 \ + HOST=x86_64-unknown-linux \ + TOOL=x86_64-linux-gnu \ + TARGET=x86_64-unknown-linux-gnu \ + CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc \ + CC_X86_64_UNKNOWN_LINUX_GNU=x86_64-linux-gnu-gcc \ + CXX_X86_64_UNKNOWN_LINUX_GNU=x86_64-linux-gnu-g++ \ + BUILD_MODE=release + +ENV \ + TOOLCHAIN=stable \ + DEBIAN_FRONTEND=noninteractive \ + PKG_CONFIG_ALLOW_CROSS=1 \ + PKG_CONFIG_PATH=/usr/lib/$TOOL/pkgconfig:/usr/lib/pkgconfig \ + LD_LIBRARY_PATH=/usr/lib/$TOOL:/usr/$TOOL/lib \ + LD_RUN_PATH=/usr/lib/$TOOL:/usr/$TOOL/lib \ + LDFLAGS="-L/usr/lib/$TOOL -L/usr/$TOOL/lib -Wl,-rpath-link,/usr/lib/$TOOL -Wl,-rpath-link,/usr/$TOOL/lib" \ + CFLAGS="-I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" \ + CPPFLAGS="-I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" RUN \ - apt-get update && \ - apt-get upgrade -y && \ + sed 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch-=amd64,i386] http:\/\/ports.ubuntu.com\/ubuntu-ports\//g' /etc/apt/sources.list > /etc/apt/sources.list.d/ports.list && \ + sed -i 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch=amd64,i386] http:\/\/\1.archive.ubuntu.com\/ubuntu\//g' /etc/apt/sources.list && \ addgroup --gid 991 build && \ adduser \ --disabled-password \ @@ -10,167 +39,174 @@ RUN \ --ingroup build \ --uid 991 \ --home /opt/build \ - build - -ADD https://sh.rustup.rs /opt/build/rustup.sh - -RUN \ - chown -R build:build /opt/build - -USER build -WORKDIR /opt/build - -ENV \ - PATH=$PATH:/opt/build/.cargo/bin \ - TOOLCHAIN=stable \ - HOST=x86_64-unknown-linux \ - TARGET=x86_64-unknown-linux-gnu \ - TOOL=x86_64-linux-gnu \ - ARCH=amd64 - -RUN \ - chmod +x rustup.sh && \ - ./rustup.sh --default-toolchain $TOOLCHAIN --profile minimal -y && \ - rustup target add $TARGET - -FROM x86_64-builder as builder - -USER root - -ADD https://imagemagick.org/download/ImageMagick.tar.gz ./ - -RUN \ + build && \ dpkg --add-architecture $ARCH && \ apt-get update && \ - apt-get -y install \ - libgexiv2-dev:$ARCH \ + apt-get upgrade -y && \ + apt-get install -y \ + pkg-config \ + build-essential \ + crossbuild-essential-$ARCH + +WORKDIR /opt/build + + +# Environment for ImageMagick +FROM cross-build as imagemagick-builder + +RUN \ + apt-get install -y \ libltdl-dev:$ARCH \ libjpeg-dev:$ARCH \ libpng-dev:$ARCH \ libwebp-dev:$ARCH \ liblzma-dev:$ARCH \ - llvm-dev \ - libclang-dev \ - clang && \ - chown build:build ImageMagick.tar.gz + libxml2-dev:$ARCH +ADD --chown=build:build https://imagemagick.org/download/ImageMagick.tar.gz /opt/build/ImageMagick.tar.gz USER build RUN \ - tar xvzf ImageMagick.tar.gz && \ + tar zxf ImageMagick.tar.gz && \ mv ImageMagick-* ImageMagick WORKDIR /opt/build/ImageMagick -ENV \ - USER=build \ - PKG_CONFIG_ALLOW_CROSS=1 \ - PKG_CONFIG_PATH=/usr/lib/$TOOL/pkgconfig:/usr/lib/pkgconfig \ - LD_LIBRARY_PATH=/usr/lib/$TOOL \ - LD_RUN_PATH=$LD_RUN_PATH:/usr/lib/$TOOL \ - LDFLAGS="$LDFLAGS -L/usr/lib/$TOOL -Wl,-rpath-link,/usr/lib/$TOOL" \ - CFLAGS="$CFLAGS -I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" \ - CPPFLAGS="$CPPFLAGS -I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" - RUN \ ./configure \ - CC=$TOOL-gcc \ - CXX=$TOOL-g++ \ - --prefix=/imagemagick \ - --with-modules \ - --enable-shared \ - --disable-static \ - --without-perl \ - --with-xml=yes \ - --with-png=yes \ - --with-jpeg=yes \ - --with-webp=yes \ - --host=$HOST && \ + CC=$TOOL-gcc \ + CXX=$TOOL-g++ \ + --enable-shared \ + --with-modules \ + --disable-static \ + --disable-docs \ + --prefix=/usr/local \ + --with-utilities=no \ + --without-perl \ + --with-xml=yes \ + --with-png=yes \ + --with-jpeg=yes \ + --with-webp=yes \ + --host=$HOST && \ make USER root RUN \ make install && \ - ldconfig /imagemagick/lib + ldconfig /usr/local/lib +# Environment for Rust +FROM cross-build as rust + +RUN \ + apt-get install -y curl + +ENV \ + PATH=$PATH:/opt/build/.cargo/bin + +ADD --chown=build:build https://sh.rustup.rs /opt/build/rustup.sh + +USER build + +RUN \ + chmod +x rustup.sh && \ + ./rustup.sh --default-toolchain $TOOLCHAIN --profile minimal -y && \ + rustup target add $TARGET + +USER root + + +# Environment for pict-rs +FROM cross-build as pict-rs-builder + +RUN \ + apt-get install -y \ + libgexiv2-dev:$ARCH \ + libxml2:$ARCH \ + libltdl7:$ARCH \ + llvm-dev \ + libclang-dev \ + clang + +ENV \ + PATH=$PATH:/opt/build/.cargo/bin \ + PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig \ + LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib \ + LD_RUN_PATH=$LD_RUN_PATH:/usr/local/lib \ + LDFLAGS="$LDFLAGS -L/usr/local/lib" \ + IMAGE_MAGICK_LIB_DIRS=/usr/local/lib \ + IMAGE_MAGICK_INCLUDE_DIRS=/usr/local/include/ImageMagick-7 \ + CFLAGS="$CFLAGS -I/usr/local/include/ImageMagick-7" \ + CPPFLAGS="$CPPFLAGS -I/usr/local/include/ImageMagick-7" \ + RUSTFLAGS="-L/usr/lib/$TOOL -C link-arg=-Wl,-rpath-link,/usr/lib/$TOOL -L/usr/$TOOL/lib -C link-arg=-Wl,-rpath-link,/usr/$TOOL/lib" + +COPY --from=rust --chown=build:build /opt/build/.cargo /opt/build/.cargo +COPY --from=rust --chown=build:build /opt/build/.rustup /opt/build/.rustup +COPY --from=imagemagick-builder /usr/local/ /usr/local + USER build WORKDIR /opt/build RUN \ - cargo new repo + USER=build cargo new repo WORKDIR /opt/build/repo -COPY Cargo.toml Cargo.lock ./ - -USER root -RUN \ - chown -R build:build ./ - -USER build - -ENV \ - LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/imagemagick/lib \ - LD_RUN_PATH=$LD_RUN_PATH:/imagemagick/lib \ - LDFLAGS="$LDFLAGS -L/imagemagick/lib" \ - RUSTFLAGS="-L/usr/lib/$TOOL -C link-arg=-Wl,-rpath-link,/usr/lib/$TOOL" \ - IMAGE_MAGICK_LIB_DIRS=/imagemagick/lib \ - IMAGE_MAGICK_INCLUDE_DIRS=/imagemagick/include/ImageMagick-7 \ - PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/imagemagick/lib/pkgconfig \ - CFLAGS="$CFLAGS -I/imagemagick/include/ImageMagick-7" \ - CPPFLAGS="$CPPFLAGS -I/imagemagick/include/ImageMagick-7" +COPY --chown=build:build Cargo.toml Cargo.lock ./ RUN \ mkdir -p ./src && \ echo 'fn main() { println!("Dummy") }' > ./src/main.rs && \ - cargo build --release && \ - rm -rf ./src + USER=build cargo build --$BUILD_MODE && \ + rm -rf ./src && \ + rm -rf ./target/$BUILD_MODE/deps/pict_rs-* -COPY src ./src/ - -USER root -RUN \ - chown -R build:build ./src && \ - rm -r ./target/release/deps/pict_rs-* - -USER build - -RUN cargo build --release --frozen - -FROM ubuntu:20.04 - -ARG UID=1000 -ARG GID=1000 -ARG BINARY=pict-rs -ARG TARGET=x86_64-unknown-linux-gnu +COPY --chown=build:build src ./src/ + +RUN \ + cargo build --$BUILD_MODE --frozen + +# Producing target binary +FROM target-env + +ARG UID=991 +ARG GID=991 RUN \ - apt-get update && \ - apt-get -y upgrade && \ - apt-get -y install \ - tini \ - libgexiv2-2 \ - libgomp1 \ - libltdl7 && \ addgroup --gid $GID pictrs && \ adduser \ --disabled-password \ --gecos "" \ --ingroup pictrs \ --uid $UID \ - --home /opt/pictrs \ - pictrs + --home /opt/pict-rs \ + pictrs && \ + apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y \ + libgexiv2-2 \ + libpng16-16 \ + libjpeg8 \ + libwebp6 \ + libwebpdemux2 \ + libwebpmux3 \ + libltdl7 \ + libgomp1 \ + libxml2 \ + tini -COPY --from=builder /imagemagick /imagemagick -COPY --from=builder /opt/build/repo/target/release/$BINARY /usr/bin/$BINARY +COPY --from=pict-rs-builder /opt/build/repo/target/$BUILD_MODE/pict-rs /usr/local/bin/pict-rs +COPY --from=imagemagick-builder /usr/local /usr/local + +ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib VOLUME /mnt -WORKDIR /opt/pictrs +WORKDIR /opt/pict-rs USER pictrs EXPOSE 8080 ENTRYPOINT ["/usr/bin/tini", "--"] -CMD ["/usr/bin/pict-rs", "-p", "/mnt", "-a", "0.0.0.0:8080"] +CMD ["/usr/local/bin/pict-rs", "-p", "/mnt"] diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index 138529e..48a94b0 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -12,6 +12,6 @@ services: - "127.0.0.1:8080:8080" restart: always environment: - - PICTRS_PATH=/app/data + - RUST_LOG=info,pict_rs=debug volumes: - ./volumes/pictrs:/mnt diff --git a/docker/prod/Dockerfile.amd64 b/docker/prod/Dockerfile.amd64 index 21b77f1..0e9d098 100644 --- a/docker/prod/Dockerfile.amd64 +++ b/docker/prod/Dockerfile.amd64 @@ -1,8 +1,37 @@ -FROM rustembedded/cross:x86_64-unknown-linux-gnu AS x86_64-builder +# Target environment +FROM amd64/ubuntu:20.04 as target-env + +ENV \ + TARGET=x86_64-unknown-linux-gnu \ + BUILD_MODE=release + +# Basic cross-build environment +FROM ubuntu:20.04 as cross-build + +ENV \ + ARCH=amd64 \ + HOST=x86_64-unknown-linux \ + TOOL=x86_64-linux-gnu \ + TARGET=x86_64-unknown-linux-gnu \ + CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc \ + CC_X86_64_UNKNOWN_LINUX_GNU=x86_64-linux-gnu-gcc \ + CXX_X86_64_UNKNOWN_LINUX_GNU=x86_64-linux-gnu-g++ \ + BUILD_MODE=release + +ENV \ + TOOLCHAIN=stable \ + DEBIAN_FRONTEND=noninteractive \ + PKG_CONFIG_ALLOW_CROSS=1 \ + PKG_CONFIG_PATH=/usr/lib/$TOOL/pkgconfig:/usr/lib/pkgconfig \ + LD_LIBRARY_PATH=/usr/lib/$TOOL:/usr/$TOOL/lib \ + LD_RUN_PATH=/usr/lib/$TOOL:/usr/$TOOL/lib \ + LDFLAGS="-L/usr/lib/$TOOL -L/usr/$TOOL/lib -Wl,-rpath-link,/usr/lib/$TOOL -Wl,-rpath-link,/usr/$TOOL/lib" \ + CFLAGS="-I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" \ + CPPFLAGS="-I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" RUN \ - apt-get update && \ - apt-get upgrade -y && \ + sed 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch-=amd64,i386] http:\/\/ports.ubuntu.com\/ubuntu-ports\//g' /etc/apt/sources.list > /etc/apt/sources.list.d/ports.list && \ + sed -i 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch=amd64,i386] http:\/\/\1.archive.ubuntu.com\/ubuntu\//g' /etc/apt/sources.list && \ addgroup --gid 991 build && \ adduser \ --disabled-password \ @@ -10,153 +39,168 @@ RUN \ --ingroup build \ --uid 991 \ --home /opt/build \ - build - -ADD https://sh.rustup.rs /opt/build/rustup.sh - -RUN \ - chown -R build:build /opt/build - -USER build -WORKDIR /opt/build - -ENV \ - PATH=$PATH:/opt/build/.cargo/bin \ - TOOLCHAIN=stable \ - HOST=x86_64-unknown-linux \ - TARGET=x86_64-unknown-linux-gnu \ - TOOL=x86_64-linux-gnu \ - ARCH=amd64 - -RUN \ - chmod +x rustup.sh && \ - ./rustup.sh --default-toolchain $TOOLCHAIN --profile minimal -y && \ - rustup target add $TARGET - - -FROM x86_64-builder as builder - -USER root - -ADD https://imagemagick.org/download/ImageMagick.tar.gz ./ - -RUN \ + build && \ dpkg --add-architecture $ARCH && \ apt-get update && \ - apt-get -y install \ - libgexiv2-dev:$ARCH \ + apt-get upgrade -y && \ + apt-get install -y \ + pkg-config \ + build-essential \ + crossbuild-essential-$ARCH + +WORKDIR /opt/build + + +# Environment for ImageMagick +FROM cross-build as imagemagick-builder + +RUN \ + apt-get install -y \ libltdl-dev:$ARCH \ libjpeg-dev:$ARCH \ libpng-dev:$ARCH \ libwebp-dev:$ARCH \ - libxml2-dev:$ARCH \ liblzma-dev:$ARCH \ - llvm-dev \ - libclang-dev \ - clang && \ - chown build:build ImageMagick.tar.gz + libxml2-dev:$ARCH +ADD --chown=build:build https://imagemagick.org/download/ImageMagick.tar.gz /opt/build/ImageMagick.tar.gz USER build RUN \ - tar xzf ImageMagick.tar.gz && \ + tar zxf ImageMagick.tar.gz && \ mv ImageMagick-* ImageMagick WORKDIR /opt/build/ImageMagick -ENV \ - USER=build \ - PKG_CONFIG_ALLOW_CROSS=1 \ - PKG_CONFIG_PATH=/usr/lib/$TOOL/pkgconfig:/usr/lib/pkgconfig \ - LD_LIBRARY_PATH=/usr/lib/$TOOL \ - LD_RUN_PATH=$LD_RUN_PATH:/usr/lib/$TOOL \ - LDFLAGS="$LDFLAGS -L/usr/lib/$TOOL -Wl,-rpath-link,/usr/lib/$TOOL" \ - CFLAGS="$CFLAGS -I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" \ - CPPFLAGS="$CPPFLAGS -I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" - RUN \ ./configure \ - CC=$TOOL-gcc \ - CXX=$TOOL-g++ \ - --prefix=/imagemagick \ - --disable-docs \ - --with-modules \ - --enable-shared \ - --disable-static \ - --without-perl \ - --with-xml=yes \ - --with-png=yes \ - --with-jpeg=yes \ - --with-webp=yes \ - --host=$HOST && \ + CC=$TOOL-gcc \ + CXX=$TOOL-g++ \ + --enable-shared \ + --with-modules \ + --disable-static \ + --disable-docs \ + --prefix=/usr/local \ + --with-utilities=no \ + --without-perl \ + --with-xml=yes \ + --with-png=yes \ + --with-jpeg=yes \ + --with-webp=yes \ + --host=$HOST && \ make USER root RUN \ make install && \ - ldconfig /imagemagick/lib + ldconfig /usr/local/lib + + +# Environment for Rust +FROM cross-build as rust + +RUN \ + apt-get install -y curl + +ENV \ + PATH=$PATH:/opt/build/.cargo/bin + +ADD --chown=build:build https://sh.rustup.rs /opt/build/rustup.sh USER build -WORKDIR /opt/build +RUN \ + chmod +x rustup.sh && \ + ./rustup.sh --default-toolchain $TOOLCHAIN --profile minimal -y && \ + rustup target add $TARGET -ARG TAG=master -ARG REPOSITORY=https://git.asonix.dog/asonix/pict-rs -ARG BINARY=pict-rs +USER root + + +# Environment for pict-rs +FROM cross-build as pict-rs-builder RUN \ - git clone -b $TAG $REPOSITORY repo - -WORKDIR /opt/build/repo + apt-get install -y \ + libgexiv2-dev:$ARCH \ + libxml2:$ARCH \ + libltdl7:$ARCH \ + llvm-dev \ + libclang-dev \ + clang ENV \ - LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/imagemagick/lib \ - LD_RUN_PATH=$LD_RUN_PATH:/imagemagick/lib \ - LDFLAGS="$LDFLAGS -L/imagemagick/lib" \ - RUSTFLAGS="-L/usr/lib/$TOOL -C link-arg=-Wl,-rpath-link,/usr/lib/$TOOL" \ - IMAGE_MAGICK_LIB_DIRS=/imagemagick/lib \ - IMAGE_MAGICK_INCLUDE_DIRS=/imagemagick/include/ImageMagick-7 \ - PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/imagemagick/lib/pkgconfig \ - CFLAGS="$CFLAGS -I/imagemagick/include/ImageMagick-7" \ - CPPFLAGS="$CPPFLAGS -I/imagemagick/include/ImageMagick-7" + PATH=$PATH:/opt/build/.cargo/bin \ + PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig \ + LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib \ + LD_RUN_PATH=$LD_RUN_PATH:/usr/local/lib \ + LDFLAGS="$LDFLAGS -L/usr/local/lib" \ + IMAGE_MAGICK_LIB_DIRS=/usr/local/lib \ + IMAGE_MAGICK_INCLUDE_DIRS=/usr/local/include/ImageMagick-7 \ + CFLAGS="$CFLAGS -I/usr/local/include/ImageMagick-7" \ + CPPFLAGS="$CPPFLAGS -I/usr/local/include/ImageMagick-7" \ + RUSTFLAGS="-L/usr/lib/$TOOL -C link-arg=-Wl,-rpath-link,/usr/lib/$TOOL -L/usr/$TOOL/lib -C link-arg=-Wl,-rpath-link,/usr/$TOOL/lib" + +COPY --from=rust --chown=build:build /opt/build/.cargo /opt/build/.cargo +COPY --from=rust --chown=build:build /opt/build/.rustup /opt/build/.rustup +COPY --from=imagemagick-builder /usr/local/ /usr/local + +ARG TAG=master +ARG GIT_REPOSITORY=https://git.asonix.dog/asonix/pict-rs + +ADD --chown=build:build $GIT_REPOSITORY/archive/$TAG.tar.gz /opt/build/$TAG.tar.gz + +USER build RUN \ - cargo build --release --target $TARGET && \ - $TOOL-strip target/$TARGET/release/$BINARY + tar zxf $TAG.tar.gz -FROM amd64/ubuntu:20.04 +WORKDIR /opt/build/pict-rs + +RUN \ + USER=build cargo build --target=$TARGET --$BUILD_MODE && \ + $TOOL-strip /opt/build/pict-rs/target/$TARGET/$BUILD_MODE/pict-rs + + +# Producing target binary +FROM target-env -ARG TARGET=x86_64-unknown-linux-gnu ARG UID=991 ARG GID=991 -ARG BINARY=pict-rs RUN \ - apt-get update && \ - apt-get -y upgrade && \ - apt-get -y install \ - tini \ - libgexiv2-2 \ - libgomp1 \ - libltdl7 && \ addgroup --gid $GID pictrs && \ adduser \ --disabled-password \ --gecos "" \ --ingroup pictrs \ --uid $UID \ - --home /opt/pictrs \ + --home /opt/pict-rs \ pictrs && \ - chown -R pictrs:pictrs /mnt + apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y \ + libgexiv2-2 \ + libpng16-16 \ + libjpeg8 \ + libwebp6 \ + libwebpdemux2 \ + libwebpmux3 \ + libltdl7 \ + libgomp1 \ + libxml2 \ + tini -COPY --from=builder /imagemagick /imagemagick -COPY --from=builder /opt/build/repo/target/$TARGET/release/$BINARY /usr/bin/$BINARY +COPY --from=pict-rs-builder /opt/build/pict-rs/target/$TARGET/$BUILD_MODE/pict-rs /usr/local/bin/pict-rs +COPY --from=imagemagick-builder /usr/local /usr/local + +ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib VOLUME /mnt -WORKDIR /opt/pictrs +WORKDIR /opt/pict-rs USER pictrs EXPOSE 8080 ENTRYPOINT ["/usr/bin/tini", "--"] -CMD ["/usr/bin/pict-rs", "-p", "/mnt", "-a", "0.0.0.0:8080", "-w", "thumbnail"] +CMD ["/usr/local/bin/pict-rs", "-p", "/mnt"] diff --git a/docker/prod/Dockerfile.arm32v7 b/docker/prod/Dockerfile.arm32v7 index c71dde2..462c3c7 100644 --- a/docker/prod/Dockerfile.arm32v7 +++ b/docker/prod/Dockerfile.arm32v7 @@ -1,8 +1,37 @@ -FROM rustembedded/cross:arm-unknown-linux-gnueabihf AS arm32v7-builder +# Target environment +FROM arm32v7/ubuntu:20.04 as target-env + +ENV \ + TARGET=armv7-unknown-linux-gnueabihf \ + BUILD_MODE=release + +# Basic cross-build environment +FROM ubuntu:20.04 as cross-build + +ENV \ + ARCH=armhf \ + HOST=arm-unknown-linux \ + TOOL=arm-linux-gnueabihf \ + TARGET=armv7-unknown-linux-gnueabihf \ + CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CC_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \ + CXX_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ \ + BUILD_MODE=release + +ENV \ + TOOLCHAIN=stable \ + DEBIAN_FRONTEND=noninteractive \ + PKG_CONFIG_ALLOW_CROSS=1 \ + PKG_CONFIG_PATH=/usr/lib/$TOOL/pkgconfig:/usr/lib/pkgconfig \ + LD_LIBRARY_PATH=/usr/lib/$TOOL:/usr/$TOOL/lib \ + LD_RUN_PATH=/usr/lib/$TOOL:/usr/$TOOL/lib \ + LDFLAGS="-L/usr/lib/$TOOL -L/usr/$TOOL/lib -Wl,-rpath-link,/usr/lib/$TOOL -Wl,-rpath-link,/usr/$TOOL/lib" \ + CFLAGS="-I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" \ + CPPFLAGS="-I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" RUN \ - apt-get update && \ - apt-get upgrade -y && \ + sed 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch-=amd64,i386] http:\/\/ports.ubuntu.com\/ubuntu-ports\//g' /etc/apt/sources.list > /etc/apt/sources.list.d/ports.list && \ + sed -i 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch=amd64,i386] http:\/\/\1.archive.ubuntu.com\/ubuntu\//g' /etc/apt/sources.list && \ addgroup --gid 991 build && \ adduser \ --disabled-password \ @@ -10,156 +39,169 @@ RUN \ --ingroup build \ --uid 991 \ --home /opt/build \ - build - -ADD https://sh.rustup.rs /opt/build/rustup.sh - -RUN \ - chown -R build:build /opt/build - -USER build -WORKDIR /opt/build - -ENV \ - PATH=$PATH:/opt/build/.cargo/bin \ - TOOLCHAIN=stable \ - HOST=arm-unknown-linux \ - TARGET=arm-unknown-linux-gnueabihf \ - TOOL=arm-linux-gnueabihf \ - ARCH=armhf - -RUN \ - chmod +x rustup.sh && \ - ./rustup.sh --default-toolchain $TOOLCHAIN --profile minimal -y && \ - rustup target add $TARGET - - -FROM arm32v7-builder as builder - -USER root - -ADD https://imagemagick.org/download/ImageMagick.tar.gz ./ - -RUN \ + build && \ dpkg --add-architecture $ARCH && \ apt-get update && \ - apt-get -y install \ - libgexiv2-dev:$ARCH \ + apt-get upgrade -y && \ + apt-get install -y \ + pkg-config \ + build-essential \ + crossbuild-essential-$ARCH + +WORKDIR /opt/build + + +# Environment for ImageMagick +FROM cross-build as imagemagick-builder + +RUN \ + apt-get install -y \ libltdl-dev:$ARCH \ libjpeg-dev:$ARCH \ libpng-dev:$ARCH \ libwebp-dev:$ARCH \ - libxml2-dev:$ARCH \ liblzma-dev:$ARCH \ - libc6-dev-$ARCH-cross \ - llvm-dev \ - libclang-dev \ - clang \ - libexpat1-dev:$ARCH && \ - chown build:build ImageMagick.tar.gz + libxml2-dev:$ARCH +ADD --chown=build:build https://imagemagick.org/download/ImageMagick.tar.gz /opt/build/ImageMagick.tar.gz USER build RUN \ - tar xzf ImageMagick.tar.gz && \ + tar zxf ImageMagick.tar.gz && \ mv ImageMagick-* ImageMagick WORKDIR /opt/build/ImageMagick -ENV \ - USER=build \ - PKG_CONFIG_ALLOW_CROSS=1 \ - PKG_CONFIG_PATH=/usr/lib/$TOOL/pkgconfig:/usr/lib/pkgconfig \ - LD_LIBRARY_PATH=/usr/lib/$TOOL \ - LD_RUN_PATH=$LD_RUN_PATH:/usr/lib/$TOOL \ - LDFLAGS="$LDFLAGS -L/lib/$TOOL -L/usr/lib/$TOOL -Wl,-rpath-link,/usr/lib/$TOOL" \ - CFLAGS="$CFLAGS -I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" \ - CPPFLAGS="$CPPFLAGS -I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" - RUN \ ./configure \ - CC=$TOOL-gcc \ - CXX=$TOOL-g++ \ - --prefix=/imagemagick \ - --disable-docs \ - --with-modules \ - --enable-shared \ - --disable-static \ - --without-perl \ - --with-xml=yes \ - --with-png=yes \ - --with-jpeg=yes \ - --with-webp=yes \ - --host=$HOST && \ + CC=$TOOL-gcc \ + CXX=$TOOL-g++ \ + --enable-shared \ + --with-modules \ + --disable-static \ + --disable-docs \ + --prefix=/usr/local \ + --with-utilities=no \ + --without-perl \ + --with-xml=yes \ + --with-png=yes \ + --with-jpeg=yes \ + --with-webp=yes \ + --host=$HOST && \ make USER root RUN \ make install && \ - ldconfig /imagemagick/lib && \ - rm -r /usr/include/x86_64-linux-gnu + ldconfig /usr/local/lib + + +# Environment for Rust +FROM cross-build as rust + +RUN \ + apt-get install -y curl + +ENV \ + PATH=$PATH:/opt/build/.cargo/bin + +ADD --chown=build:build https://sh.rustup.rs /opt/build/rustup.sh USER build -WORKDIR /opt/build +RUN \ + chmod +x rustup.sh && \ + ./rustup.sh --default-toolchain $TOOLCHAIN --profile minimal -y && \ + rustup target add $TARGET -ARG TAG=master -ARG REPOSITORY=https://git.asonix.dog/asonix/pict-rs -ARG BINARY=pict-rs +USER root + + +# Environment for pict-rs +FROM cross-build as pict-rs-builder RUN \ - git clone -b $TAG $REPOSITORY repo - -WORKDIR /opt/build/repo + apt-get install -y \ + libgexiv2-dev:$ARCH \ + libxml2:$ARCH \ + libltdl7:$ARCH \ + llvm-dev \ + libclang-dev \ + clang && \ + rm -rf /usr/include/x86_64-linux-gnu ENV \ - LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/imagemagick/lib \ - LD_RUN_PATH=$LD_RUN_PATH:/imagemagick/lib \ - LDFLAGS="$LDFLAGS -L/imagemagick/lib" \ - RUSTFLAGS="-L/usr/lib/$TOOL -L/lib/$TOOL -C link-arg=-Wl,-rpath-link,/usr/lib/$TOOL -C link-arg=-Wl,-rpath-link,/lib/$TOOL" \ - IMAGE_MAGICK_LIB_DIRS=/imagemagick/lib \ - IMAGE_MAGICK_INCLUDE_DIRS=/imagemagick/include/ImageMagick-7 \ - PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/imagemagick/lib/pkgconfig \ - CFLAGS="$CFLAGS -I/imagemagick/include/ImageMagick-7" \ - CPPFLAGS="$CPPFLAGS -I/imagemagick/include/ImageMagick-7" + PATH=$PATH:/opt/build/.cargo/bin \ + PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig \ + LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib \ + LD_RUN_PATH=$LD_RUN_PATH:/usr/local/lib \ + LDFLAGS="$LDFLAGS -L/usr/local/lib" \ + IMAGE_MAGICK_LIB_DIRS=/usr/local/lib \ + IMAGE_MAGICK_INCLUDE_DIRS=/usr/local/include/ImageMagick-7 \ + CFLAGS="$CFLAGS -I/usr/local/include/ImageMagick-7" \ + CPPFLAGS="$CPPFLAGS -I/usr/local/include/ImageMagick-7" \ + RUSTFLAGS="-L/usr/lib/$TOOL -C link-arg=-Wl,-rpath-link,/usr/lib/$TOOL -L/usr/$TOOL/lib -C link-arg=-Wl,-rpath-link,/usr/$TOOL/lib" + +COPY --from=rust --chown=build:build /opt/build/.cargo /opt/build/.cargo +COPY --from=rust --chown=build:build /opt/build/.rustup /opt/build/.rustup +COPY --from=imagemagick-builder /usr/local/ /usr/local + +ARG TAG=master +ARG GIT_REPOSITORY=https://git.asonix.dog/asonix/pict-rs + +ADD --chown=build:build $GIT_REPOSITORY/archive/$TAG.tar.gz /opt/build/$TAG.tar.gz + +USER build RUN \ - cargo build --release --target $TARGET && \ - $TOOL-strip target/$TARGET/release/$BINARY + tar zxf $TAG.tar.gz -FROM arm32v7/ubuntu:20.04 +WORKDIR /opt/build/pict-rs + +RUN \ + USER=build cargo build --target=$TARGET --$BUILD_MODE && \ + $TOOL-strip /opt/build/pict-rs/target/$TARGET/$BUILD_MODE/pict-rs + + +# Producing target binary +FROM target-env -ARG TARGET=arm-unknown-linux-gnueabihf ARG UID=991 ARG GID=991 -ARG BINARY=pict-rs RUN \ - apt-get update && \ - apt-get -y upgrade && \ - apt-get -y install \ - tini \ - libgexiv2-2 \ - libgomp1 \ - libltdl7 && \ addgroup --gid $GID pictrs && \ adduser \ --disabled-password \ --gecos "" \ --ingroup pictrs \ --uid $UID \ - --home /opt/pictrs \ + --home /opt/pict-rs \ pictrs && \ - chown -R pictrs:pictrs /mnt + apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y \ + libgexiv2-2 \ + libpng16-16 \ + libjpeg8 \ + libwebp6 \ + libwebpdemux2 \ + libwebpmux3 \ + libltdl7 \ + libgomp1 \ + libxml2 \ + tini -COPY --from=builder /imagemagick /imagemagick -COPY --from=builder /opt/build/repo/target/$TARGET/release/$BINARY /usr/bin/$BINARY +COPY --from=pict-rs-builder /opt/build/pict-rs/target/$TARGET/$BUILD_MODE/pict-rs /usr/local/bin/pict-rs +COPY --from=imagemagick-builder /usr/local /usr/local + +ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib VOLUME /mnt -WORKDIR /opt/pictrs +WORKDIR /opt/pict-rs USER pictrs EXPOSE 8080 ENTRYPOINT ["/usr/bin/tini", "--"] -CMD ["/usr/bin/pict-rs", "-p", "/mnt", "-a", "0.0.0.0:8080", "-w", "thumbnail"] +CMD ["/usr/local/bin/pict-rs", "-p", "/mnt"] diff --git a/docker/prod/Dockerfile.arm64v8 b/docker/prod/Dockerfile.arm64v8 index 39395e1..d9f2212 100644 --- a/docker/prod/Dockerfile.arm64v8 +++ b/docker/prod/Dockerfile.arm64v8 @@ -1,8 +1,37 @@ -FROM rustembedded/cross:aarch64-unknown-linux-gnu AS aarch64-builder +# Target environment +FROM arm64v8/ubuntu:20.04 as target-env + +ENV \ + TARGET=aarch64-unknown-linux-gnu \ + BUILD_MODE=release + +# Basic cross-build environment +FROM ubuntu:20.04 as cross-build + +ENV \ + ARCH=arm64 \ + HOST=aarch64-unknown-linux \ + TOOL=aarch64-linux-gnu \ + TARGET=aarch64-unknown-linux-gnu \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + CC_AARCH64_UNKNOWN_LINUX_GNU=aarch64-linux-gnu-gcc \ + CXX_AARCH64_UNKNOWN_LINUX_GNU=aarch64-linux-gnu-g++ \ + BUILD_MODE=release + +ENV \ + TOOLCHAIN=stable \ + DEBIAN_FRONTEND=noninteractive \ + PKG_CONFIG_ALLOW_CROSS=1 \ + PKG_CONFIG_PATH=/usr/lib/$TOOL/pkgconfig:/usr/lib/pkgconfig \ + LD_LIBRARY_PATH=/usr/lib/$TOOL:/usr/$TOOL/lib \ + LD_RUN_PATH=/usr/lib/$TOOL:/usr/$TOOL/lib \ + LDFLAGS="-L/usr/lib/$TOOL -L/usr/$TOOL/lib -Wl,-rpath-link,/usr/lib/$TOOL -Wl,-rpath-link,/usr/$TOOL/lib" \ + CFLAGS="-I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" \ + CPPFLAGS="-I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" RUN \ - apt-get update && \ - apt-get upgrade -y && \ + sed 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch-=amd64,i386] http:\/\/ports.ubuntu.com\/ubuntu-ports\//g' /etc/apt/sources.list > /etc/apt/sources.list.d/ports.list && \ + sed -i 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch=amd64,i386] http:\/\/\1.archive.ubuntu.com\/ubuntu\//g' /etc/apt/sources.list && \ addgroup --gid 991 build && \ adduser \ --disabled-password \ @@ -10,155 +39,169 @@ RUN \ --ingroup build \ --uid 991 \ --home /opt/build \ - build - -ADD https://sh.rustup.rs /opt/build/rustup.sh - -RUN \ - chown -R build:build /opt/build - -USER build -WORKDIR /opt/build - -ENV \ - PATH=$PATH:/opt/build/.cargo/bin \ - TOOLCHAIN=stable \ - HOST=aarch64-unknown-linux \ - TARGET=aarch64-unknown-linux-gnu \ - TOOL=aarch64-linux-gnu \ - ARCH=arm64 - -RUN \ - chmod +x rustup.sh && \ - ./rustup.sh --default-toolchain $TOOLCHAIN --profile minimal -y && \ - rustup target add $TARGET - - -FROM aarch64-builder as builder - -USER root - -ADD https://imagemagick.org/download/ImageMagick.tar.gz ./ - -RUN \ + build && \ dpkg --add-architecture $ARCH && \ apt-get update && \ - apt-get -y install \ - libgexiv2-dev:$ARCH \ + apt-get upgrade -y && \ + apt-get install -y \ + pkg-config \ + build-essential \ + crossbuild-essential-$ARCH + +WORKDIR /opt/build + + +# Environment for ImageMagick +FROM cross-build as imagemagick-builder + +RUN \ + apt-get install -y \ libltdl-dev:$ARCH \ libjpeg-dev:$ARCH \ libpng-dev:$ARCH \ libwebp-dev:$ARCH \ - libxml2-dev:$ARCH \ liblzma-dev:$ARCH \ - libc6-dev-$ARCH-cross \ - llvm-dev \ - libclang-dev \ - clang && \ - chown build:build ImageMagick.tar.gz + libxml2-dev:$ARCH +ADD --chown=build:build https://imagemagick.org/download/ImageMagick.tar.gz /opt/build/ImageMagick.tar.gz USER build RUN \ - tar xzf ImageMagick.tar.gz && \ + tar zxf ImageMagick.tar.gz && \ mv ImageMagick-* ImageMagick WORKDIR /opt/build/ImageMagick -ENV \ - USER=build \ - PKG_CONFIG_ALLOW_CROSS=1 \ - PKG_CONFIG_PATH=/usr/lib/$TOOL/pkgconfig:/usr/lib/pkgconfig \ - LD_LIBRARY_PATH=/usr/lib/$TOOL \ - LD_RUN_PATH=$LD_RUN_PATH:/usr/lib/$TOOL \ - LDFLAGS="$LDFLAGS -L/usr/lib/$TOOL -Wl,-rpath-link,/usr/lib/$TOOL" \ - CFLAGS="$CFLAGS -I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" \ - CPPFLAGS="$CPPFLAGS -I/usr/include/$TOOL -I/usr/$TOOL/include -I/usr/include" - RUN \ ./configure \ - CC=$TOOL-gcc \ - CXX=$TOOL-g++ \ - --prefix=/imagemagick \ - --disable-docs \ - --with-modules \ - --enable-shared \ - --disable-static \ - --without-perl \ - --with-xml=yes \ - --with-png=yes \ - --with-jpeg=yes \ - --with-webp=yes \ - --host=$HOST && \ + CC=$TOOL-gcc \ + CXX=$TOOL-g++ \ + --enable-shared \ + --with-modules \ + --disable-static \ + --disable-docs \ + --prefix=/usr/local \ + --with-utilities=no \ + --without-perl \ + --with-xml=yes \ + --with-png=yes \ + --with-jpeg=yes \ + --with-webp=yes \ + --host=$HOST && \ make USER root RUN \ make install && \ - ldconfig /imagemagick/lib && \ - rm -r /usr/include/x86_64-linux-gnu + ldconfig /usr/local/lib + + +# Environment for Rust +FROM cross-build as rust + +RUN \ + apt-get install -y curl + +ENV \ + PATH=$PATH:/opt/build/.cargo/bin + +ADD --chown=build:build https://sh.rustup.rs /opt/build/rustup.sh USER build -WORKDIR /opt/build +RUN \ + chmod +x rustup.sh && \ + ./rustup.sh --default-toolchain $TOOLCHAIN --profile minimal -y && \ + rustup target add $TARGET -ARG TAG=master -ARG REPOSITORY=https://git.asonix.dog/asonix/pict-rs -ARG BINARY=pict-rs +USER root + + +# Environment for pict-rs +FROM cross-build as pict-rs-builder RUN \ - git clone -b $TAG $REPOSITORY repo - -WORKDIR /opt/build/repo + apt-get install -y \ + libgexiv2-dev:$ARCH \ + libxml2:$ARCH \ + libltdl7:$ARCH \ + llvm-dev \ + libclang-dev \ + clang && \ + rm -rf /usr/include/x86_64-linux-gnu ENV \ - LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/imagemagick/lib \ - LD_RUN_PATH=$LD_RUN_PATH:/imagemagick/lib \ - LDFLAGS="$LDFLAGS -L/imagemagick/lib" \ - RUSTFLAGS="-L/usr/lib/$TOOL -C link-arg=-Wl,-rpath-link,/usr/lib/$TOOL" \ - IMAGE_MAGICK_LIB_DIRS=/imagemagick/lib \ - IMAGE_MAGICK_INCLUDE_DIRS=/imagemagick/include/ImageMagick-7 \ - PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/imagemagick/lib/pkgconfig \ - CFLAGS="$CFLAGS -I/imagemagick/include/ImageMagick-7" \ - CPPFLAGS="$CPPFLAGS -I/imagemagick/include/ImageMagick-7" + PATH=$PATH:/opt/build/.cargo/bin \ + PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig \ + LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib \ + LD_RUN_PATH=$LD_RUN_PATH:/usr/local/lib \ + LDFLAGS="$LDFLAGS -L/usr/local/lib" \ + IMAGE_MAGICK_LIB_DIRS=/usr/local/lib \ + IMAGE_MAGICK_INCLUDE_DIRS=/usr/local/include/ImageMagick-7 \ + CFLAGS="$CFLAGS -I/usr/local/include/ImageMagick-7" \ + CPPFLAGS="$CPPFLAGS -I/usr/local/include/ImageMagick-7" \ + RUSTFLAGS="-L/usr/lib/$TOOL -C link-arg=-Wl,-rpath-link,/usr/lib/$TOOL -L/usr/$TOOL/lib -C link-arg=-Wl,-rpath-link,/usr/$TOOL/lib" + +COPY --from=rust --chown=build:build /opt/build/.cargo /opt/build/.cargo +COPY --from=rust --chown=build:build /opt/build/.rustup /opt/build/.rustup +COPY --from=imagemagick-builder /usr/local/ /usr/local + +ARG TAG=master +ARG GIT_REPOSITORY=https://git.asonix.dog/asonix/pict-rs + +ADD --chown=build:build $GIT_REPOSITORY/archive/$TAG.tar.gz /opt/build/$TAG.tar.gz + +USER build RUN \ - cargo build --release --target $TARGET && \ - $TOOL-strip target/$TARGET/release/$BINARY + tar zxf $TAG.tar.gz -FROM arm64v8/ubuntu:20.04 +WORKDIR /opt/build/pict-rs + +RUN \ + USER=build cargo build --target=$TARGET --$BUILD_MODE && \ + $TOOL-strip /opt/build/pict-rs/target/$TARGET/$BUILD_MODE/pict-rs + + +# Producing target binary +FROM target-env -ARG TARGET=aarch64-unknown-linux-gnu ARG UID=991 ARG GID=991 -ARG BINARY=pict-rs RUN \ - apt-get update && \ - apt-get -y upgrade && \ - apt-get -y install \ - tini \ - libgexiv2-2 \ - libgomp1 \ - libltdl7 && \ addgroup --gid $GID pictrs && \ adduser \ --disabled-password \ --gecos "" \ --ingroup pictrs \ --uid $UID \ - --home /opt/pictrs \ + --home /opt/pict-rs \ pictrs && \ - chown -R pictrs:pictrs /mnt + apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y \ + libgexiv2-2 \ + libpng16-16 \ + libjpeg8 \ + libwebp6 \ + libwebpdemux2 \ + libwebpmux3 \ + libltdl7 \ + libgomp1 \ + libxml2 \ + tini -COPY --from=builder /imagemagick /imagemagick -COPY --from=builder /opt/build/repo/target/$TARGET/release/$BINARY /usr/bin/$BINARY +COPY --from=pict-rs-builder /opt/build/pict-rs/target/$TARGET/$BUILD_MODE/pict-rs /usr/local/bin/pict-rs +COPY --from=imagemagick-builder /usr/local /usr/local + +ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib VOLUME /mnt -WORKDIR /opt/pictrs +WORKDIR /opt/pict-rs USER pictrs EXPOSE 8080 ENTRYPOINT ["/usr/bin/tini", "--"] -CMD ["/usr/bin/pict-rs", "-p", "/mnt", "-a", "0.0.0.0:8080", "-w", "thumbnail"] +CMD ["/usr/local/bin/pict-rs", "-p", "/mnt"] diff --git a/src/config.rs b/src/config.rs index c6501e4..8961035 100644 --- a/src/config.rs +++ b/src/config.rs @@ -30,7 +30,7 @@ pub(crate) struct Config { short, long, env = "PICTRS_FORMAT", - help = "An optional image format to convert all uploaded files into, supports 'jpg' and 'png'" + help = "An optional image format to convert all uploaded files into, supports 'jpg', 'png', and 'webp'" )] format: Option, @@ -88,6 +88,7 @@ pub(crate) struct FormatError(String); pub(crate) enum Format { Jpeg, Png, + Webp, } impl std::str::FromStr for Format { @@ -97,6 +98,7 @@ impl std::str::FromStr for Format { match s { "png" => Ok(Format::Png), "jpg" => Ok(Format::Jpeg), + "webp" => Ok(Format::Webp), other => Err(FormatError(other.to_string())), } } diff --git a/src/error.rs b/src/error.rs index 676b33b..5af73b0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -68,6 +68,9 @@ pub(crate) enum UploadError { #[error("File metadata could not be parsed, {0}")] Validate(#[from] rexiv2::Rexiv2Error), + + #[error("Error in MagickWand, {0}")] + Wand(String), } impl From for UploadError { diff --git a/src/main.rs b/src/main.rs index a6cbfaf..d6e8343 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ mod validate; use self::{ config::Config, error::UploadError, middleware::Tracing, upload_manager::UploadManager, + validate::image_webp, }; const MEGABYTES: usize = 1024 * 1024; @@ -75,7 +76,7 @@ fn to_ext(mime: mime::Mime) -> &'static str { } else if mime == mime::IMAGE_GIF { ".gif" } else { - ".bmp" + ".webp" } } @@ -84,7 +85,7 @@ fn from_ext(ext: std::ffi::OsString) -> mime::Mime { Some("png") => mime::IMAGE_PNG, Some("jpg") => mime::IMAGE_JPEG, Some("gif") => mime::IMAGE_GIF, - _ => mime::IMAGE_BMP, + _ => image_webp(), } } diff --git a/src/validate.rs b/src/validate.rs index acf7223..c480c20 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -1,13 +1,37 @@ use crate::{config::Format, error::UploadError, upload_manager::tmp_file}; use actix_web::web; -use image::{io::Reader, ImageDecoder, ImageEncoder, ImageFormat}; +use image::{io::Reader, ImageFormat}; +use magick_rust::MagickWand; use rexiv2::{MediaType, Metadata}; use std::{ fs::File, io::{BufReader, BufWriter, Write}, path::PathBuf, }; -use tracing::{debug, instrument, trace, Span}; +use tracing::{debug, error, instrument, trace, warn, Span}; + +pub(crate) trait Op { + fn op(&self, f: F) -> Result + where + F: Fn(&Self) -> Result; +} + +impl Op for MagickWand { + fn op(&self, f: F) -> Result + where + F: Fn(&Self) -> Result, + { + match f(self) { + Ok(t) => Ok(t), + Err(e) => { + if let Ok(e) = self.get_exception() { + error!("WandError: {}", e.0); + } + Err(UploadError::Wand(e.to_owned())) + } + } + } +} #[derive(Debug, thiserror::Error)] pub(crate) enum GifError { @@ -18,12 +42,21 @@ pub(crate) enum GifError { Io(#[from] std::io::Error), } +pub(crate) fn image_webp() -> mime::Mime { + "image/webp".parse().unwrap() +} + +fn ptos(p: &PathBuf) -> Result { + Ok(p.to_str().ok_or(UploadError::Path)?.to_owned()) +} + // import & export image using the image crate #[instrument] pub(crate) async fn validate_image( tmpfile: PathBuf, prescribed_format: Option, ) -> Result { + let tmpfile_str = ptos(&tmpfile)?; let span = Span::current(); let content_type = web::block(move || { @@ -39,21 +72,54 @@ pub(crate) async fn validate_image( mime::IMAGE_GIF } (Some(Format::Jpeg), MediaType::Jpeg) | (None, MediaType::Jpeg) => { - validate(&tmpfile, ImageFormat::Jpeg)?; + { + let wand = MagickWand::new(); + debug!("reading: {}", tmpfile_str); + wand.op(|w| w.read_image(&tmpfile_str))?; + debug!("format: {}", wand.op(|w| w.get_format())?); + } + + let meta = Metadata::new_from_path(&tmpfile)?; meta.clear(); meta.save_to_file(&tmpfile)?; mime::IMAGE_JPEG } (Some(Format::Png), MediaType::Png) | (None, MediaType::Png) => { - validate(&tmpfile, ImageFormat::Png)?; + { + let wand = MagickWand::new(); + debug!("reading: {}", tmpfile_str); + wand.op(|w| w.read_image(&tmpfile_str))?; + debug!("format: {}", wand.op(|w| w.get_format())?); + } + + let meta = Metadata::new_from_path(&tmpfile)?; meta.clear(); meta.save_to_file(&tmpfile)?; mime::IMAGE_PNG } + (Some(Format::Webp), MediaType::Other(webp)) | (None, MediaType::Other(webp)) + if webp == "image/webp" => + { + { + let wand = MagickWand::new(); + debug!("reading: {}", tmpfile_str); + wand.op(|w| w.read_image(&tmpfile_str))?; + + debug!("format: {}", wand.op(|w| w.get_format())?); + debug!("type: {}", wand.op(|w| Ok(w.get_type()))?); + debug!("image_type: {}", wand.op(|w| Ok(w.get_image_type()))?); + } + + // let meta = Metadata::new_from_path(&tmpfile)?; + // meta.clear(); + // meta.save_to_file(&tmpfile)?; + + image_webp() + } (Some(Format::Jpeg), _) => { let newfile = tmp_file(); convert(&tmpfile, &newfile, ImageFormat::Jpeg)?; @@ -66,13 +132,10 @@ pub(crate) async fn validate_image( mime::IMAGE_PNG } - (_, MediaType::Bmp) => { - let newfile = tmp_file(); - validate_bmp(&tmpfile, &newfile)?; - - mime::IMAGE_BMP + (_, media_type) => { + warn!("Unsupported media type, {}", media_type); + return Err(UploadError::UnsupportedFormat); } - _ => return Err(UploadError::UnsupportedFormat), }; drop(entered); @@ -112,20 +175,6 @@ fn validate(path: &PathBuf, format: ImageFormat) -> Result<(), UploadError> { Ok(()) } -#[instrument] -fn validate_bmp(from: &PathBuf, to: &PathBuf) -> Result<(), UploadError> { - debug!("Transmuting BMP"); - let decoder = image::bmp::BmpDecoder::new(BufReader::new(File::open(from)?))?; - - let mut writer = BufWriter::new(File::create(to)?); - let encoder = image::bmp::BMPEncoder::new(&mut writer); - validate_still_image(decoder, encoder)?; - - writer.flush()?; - std::fs::rename(to, from)?; - Ok(()) -} - #[instrument] fn validate_gif(from: &PathBuf, to: &PathBuf) -> Result<(), GifError> { debug!("Transmuting GIF"); @@ -157,21 +206,3 @@ fn validate_gif(from: &PathBuf, to: &PathBuf) -> Result<(), GifError> { std::fs::rename(to, from)?; Ok(()) } - -fn validate_still_image<'a, D, E>(decoder: D, encoder: E) -> Result<(), UploadError> -where - D: ImageDecoder<'a>, - E: ImageEncoder, -{ - let (width, height) = decoder.dimensions(); - let color_type = decoder.color_type(); - let total_bytes = decoder.total_bytes(); - debug!("Reading image"); - let mut decoded_bytes = vec![0u8; total_bytes as usize]; - decoder.read_image(&mut decoded_bytes)?; - - debug!("Writing image"); - encoder.write_image(&decoded_bytes, width, height, color_type)?; - - Ok(()) -}