From ebcdf9b0bced3ab7a0bf35323ebbd339af64af17 Mon Sep 17 00:00:00 2001 From: Nick Vance Date: Sat, 10 Jan 2026 21:28:04 -0800 Subject: [PATCH 1/5] Add Qt image plugins for AVIF, JXL, and HEIC/HEIF support in Docker - Add multi-stage Docker build with 7 optimized stages - Build and install Qt image plugins: qt-avif-image-plugin, qt-jpegxl-image-plugin, qt-heic-image-plugin - Build libjxl 0.10.2 from source (required version not in Ubuntu noble) - Use system packages for AVIF (libavif16) and HEIC (libheif1) - No YACReader source code changes - uses Qt's dynamic plugin loading - Improves build caching and reduces rebuild times Enables support for modern image formats without code modifications, following YACReader's Qt plugin architecture as suggested in #498 --- docker/Dockerfile | 333 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 253 insertions(+), 80 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 12c5ed4b5..fa8f6e600 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,115 +1,288 @@ -FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS builder +# ============================================================================ +# Stage 1: 7zip builder +# ============================================================================ +FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS sevenzip-builder -# version, it can be a TAG or a branch -ARG YACR_VERSION="develop" +ARG DEBIAN_FRONTEND="noninteractive" + +# Install minimal build packages for 7z compilation +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + gcc \ + g++ \ + make \ + unzip \ + wget \ + 7zip && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Download and extract 7z source +RUN mkdir -p /src/7zip && \ + cd /src/7zip && \ + wget "https://github.com/YACReader/yacreader-7z-deps/blob/main/7z2301-src.7z?raw=true" -O 7z2301-src.7z && \ + 7z x 7z2301-src.7z -o/src/7zip/lib7zip && \ + rm 7z2301-src.7z + +# Build 7z.so with RAR support +RUN cd "/src/7zip/lib7zip/CPP/7zip/Bundles/Format7zF" && \ + make -f makefile.gcc -j$(nproc) && \ + mkdir -p /app/lib/7zip && \ + cp ./_o/7z.so /app/lib/7zip + +# ============================================================================ +# Stage 2: HEIC/HEIF plugin builder +# ============================================================================ +FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS heic-plugin-builder + +ARG DEBIAN_FRONTEND="noninteractive" + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + git \ + qt6-base-dev \ + qt6-base-private-dev \ + libheif-dev \ + extra-cmake-modules \ + pkg-config && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /tmp/qt-heic +RUN git clone https://github.com/novomesk/qt-heic-image-plugin.git . && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DQT_MAJOR_VERSION=6 && \ + make -j$(nproc) && \ + make install DESTDIR=/output + +# ============================================================================ +# Stage 3: libjxl builder (0.10.2 required for JxlEncoderDistanceFromQuality) +# ============================================================================ +FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS libjxl-builder + +ARG DEBIAN_FRONTEND="noninteractive" + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + git \ + pkg-config && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /tmp/libjxl +RUN git clone --depth 1 --branch v0.10.2 https://github.com/libjxl/libjxl.git . && \ + ./deps.sh && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=OFF \ + -DJPEGXL_ENABLE_BENCHMARK=OFF \ + -DJPEGXL_ENABLE_EXAMPLES=OFF \ + -DJPEGXL_ENABLE_MANPAGES=OFF \ + -DJPEGXL_ENABLE_PLUGINS=OFF \ + -DJPEGXL_ENABLE_TOOLS=OFF \ + -DCMAKE_INSTALL_PREFIX=/usr && \ + make -j$(nproc) && \ + make install DESTDIR=/output + +# ============================================================================ +# Stage 4: JXL plugin builder (depends on libjxl 0.10.2) +# ============================================================================ +FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS jxl-plugin-builder + +ARG DEBIAN_FRONTEND="noninteractive" + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + git \ + qt6-base-dev \ + qt6-base-private-dev \ + extra-cmake-modules \ + pkg-config && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Copy libjxl 0.10.2 from previous stage +COPY --from=libjxl-builder /output/usr /usr + +WORKDIR /tmp/qt-jxl +RUN git clone https://github.com/novomesk/qt-jpegxl-image-plugin.git . && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DQT_MAJOR_VERSION=6 && \ + make -j$(nproc) && \ + make install DESTDIR=/output + +# ============================================================================ +# Stage 5: AVIF plugin builder +# ============================================================================ +FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS avif-plugin-builder -# env variables +ARG DEBIAN_FRONTEND="noninteractive" + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + git \ + qt6-base-dev \ + qt6-base-private-dev \ + libavif-dev \ + extra-cmake-modules \ + pkg-config && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /tmp/qt-avif +RUN git clone https://github.com/novomesk/qt-avif-image-plugin.git . && \ + mkdir build && cd build && \ + cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DQT_MAJOR_VERSION=6 && \ + make -j$(nproc) && \ + make install DESTDIR=/output + +# ============================================================================ +# Stage 6: YACReader builder +# ============================================================================ +FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS yacreader-builder + +ARG YACR_VERSION="develop" ARG DEBIAN_FRONTEND="noninteractive" ENV APPNAME="YACReaderLibraryServer" ENV HOME="/config" LABEL maintainer="luisangelsm" -# install build packages -RUN \ - apt-get update && \ +# Install build packages +RUN apt-get update && \ apt-get install -y --no-install-recommends \ - build-essential \ - desktop-file-utils \ - gcc \ - g++ \ - git \ - qt6-tools-dev \ - qt6-base-dev-tools \ - qmake6 \ - qmake6-bin \ - qt6-base-dev \ - qt6-multimedia-dev \ - qt6-tools-dev-tools \ - libgl-dev \ - qt6-l10n-tools \ - libqt6opengl6-dev \ - libunarr-dev \ - qt6-declarative-dev \ - libqt6svg6-dev \ - libqt6core5compat6-dev \ - libbz2-dev \ - libglu1-mesa-dev \ - liblzma-dev \ - libqt6gui6 \ - libqt6multimedia6 \ - libqt6network6 \ - libqt6qml6 \ - libqt6quickcontrols2-6 \ - qt6-image-formats-plugins \ - libqt6sql6 \ - libqt6sql6-sqlite \ - make \ - sqlite3 \ - libsqlite3-dev \ - unzip \ - wget \ - 7zip \ - 7zip-rar \ - libpoppler-qt6-dev \ - zlib1g-dev && \ + build-essential \ + desktop-file-utils \ + gcc \ + g++ \ + git \ + cmake \ + qt6-tools-dev \ + qt6-base-dev-tools \ + qmake6 \ + qmake6-bin \ + qt6-base-dev \ + qt6-multimedia-dev \ + qt6-tools-dev-tools \ + libgl-dev \ + qt6-l10n-tools \ + libqt6opengl6-dev \ + libunarr-dev \ + qt6-declarative-dev \ + libqt6svg6-dev \ + libqt6core5compat6-dev \ + libbz2-dev \ + libglu1-mesa-dev \ + liblzma-dev \ + libqt6gui6 \ + libqt6multimedia6 \ + libqt6network6 \ + libqt6qml6 \ + libqt6quickcontrols2-6 \ + qt6-image-formats-plugins \ + libqt6sql6 \ + libqt6sql6-sqlite \ + make \ + sqlite3 \ + libsqlite3-dev \ + unzip \ + wget \ + libavif-dev \ + 7zip \ + 7zip-rar \ + libpoppler-qt6-dev \ + zlib1g-dev && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* && \ ldconfig - -# clone YACReader repo +# Clone YACReader repository RUN git clone https://github.com/YACReader/yacreader.git /src/git && \ cd /src/git && \ git checkout $YACR_VERSION -# get 7zip source -RUN cd /src/git/compressed_archive && \ - wget "https://github.com/YACReader/yacreader-7z-deps/blob/main/7z2301-src.7z?raw=true" -O /src/git/compressed_archive/7z2301-src.7z && \ - 7z x /src/git/compressed_archive/7z2301-src.7z -o/src/git/compressed_archive/lib7zip +# Copy pre-built 7z library and headers +COPY --from=sevenzip-builder /src/7zip/lib7zip /src/git/compressed_archive/lib7zip +COPY --from=sevenzip-builder /app/lib/7zip /app/lib/7zip + +# Copy Qt image format plugins from separate stages +COPY --from=avif-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ + /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ +COPY --from=jxl-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ + /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ +COPY --from=heic-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ + /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ -# build yacreaderlibraryserver +# Build YACReaderLibraryServer RUN cd /src/git/YACReaderLibraryServer && \ qmake6 PREFIX=/app CONFIG+="7zip server_standalone" YACReaderLibraryServer.pro && \ qmake6 -v && \ - make && \ + make -j$(nproc) && \ make install -# install 7z.so with RAR support -RUN echo "Building and installing 7z.so with RAR support..." && \ - cd "/src/git/compressed_archive/lib7zip/CPP/7zip/Bundles/Format7zF" && \ - make -f makefile.gcc && \ - mkdir -p /app/lib/7zip && \ - cp ./_o/7z.so /app/lib/7zip - -# Stage 2: Runtime stage +# ============================================================================ +# Stage 7: Final runtime image (minimal, no build assets) +# ============================================================================ FROM ghcr.io/linuxserver/baseimage-ubuntu:noble -# env variables ENV APPNAME="YACReaderLibraryServer" ENV HOME="/config" +ENV LC_ALL="en_US.UTF-8" +ENV PATH="/app/bin:${PATH}" LABEL maintainer="luisangelsm" -# Copy the built application from the builder stage -COPY --from=builder /app /app - -# runtime packages +# Install only runtime dependencies (no build tools) RUN apt-get update && \ apt-get install -y --no-install-recommends \ - libqt6core5compat6 \ - libpoppler-qt6-3t64 \ - qt6-image-formats-plugins \ - libqt6network6t64 \ - libqt6sql6-sqlite && \ + libqt6core5compat6 \ + libpoppler-qt6-3t64 \ + qt6-image-formats-plugins \ + libqt6network6t64 \ + libqt6sql6-sqlite \ + libavif16 \ + libheif1 && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -# set ENV -ENV LC_ALL="en_US.UTF-8" \ - PATH="/app/bin:${PATH}" +# Copy YACReaderLibraryServer application from builder +COPY --from=yacreader-builder /app /app + +# Copy Qt image format plugins from plugin builders +COPY --from=avif-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ + /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ +COPY --from=jxl-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ + /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ +COPY --from=heic-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ + /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ + +# Copy libjxl 0.10.2 runtime libraries (not available in Ubuntu noble) +COPY --from=libjxl-builder /output/usr/lib/ /usr/lib/ + +# Refresh dynamic linker cache +RUN ldconfig -# copy files -COPY root.tar.gz / -# Extract the contents of root.tar.gz into the / directory -RUN tar -xvpzf /root.tar.gz -C / +# Copy linuxserver.io configuration +COPY docker/root.tar.gz / +RUN tar -xvpzf /root.tar.gz -C / && rm /root.tar.gz -# ports and volumes +# Expose server port and define volumes EXPOSE 8080 VOLUME ["/config", "/comics"] From b12ace08aa45e6253befe38d3875eee621e663bd Mon Sep 17 00:00:00 2001 From: Nick Vance Date: Sat, 10 Jan 2026 21:42:23 -0800 Subject: [PATCH 2/5] additional dockerfile optimizations for speed and caching --- docker/Dockerfile | 198 ++++++++++++++++++---------------------------- 1 file changed, 76 insertions(+), 122 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index fa8f6e600..a8b1379c3 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,87 +1,86 @@ # ============================================================================ -# Stage 1: 7zip builder +# Stage 0: Common base, defined here like a constant for multiple subsequent stages # ============================================================================ -FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS sevenzip-builder +FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS base + +# ============================================================================ +# Stage 1: build-base for all build steps +# ============================================================================ +FROM base AS plugin-base ARG DEBIAN_FRONTEND="noninteractive" -# Install minimal build packages for 7z compilation +# Install common build packages used by all plugin builders RUN apt-get update && \ apt-get install -y --no-install-recommends \ + 7zip \ build-essential \ - gcc \ + cmake \ + extra-cmake-modules \ g++ \ + gcc \ + git \ + libavif-dev \ + libheif-dev \ make \ + qt6-base-dev \ + qt6-base-private-dev \ unzip \ wget \ - 7zip && \ + pkg-config && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -# Download and extract 7z source -RUN mkdir -p /src/7zip && \ - cd /src/7zip && \ - wget "https://github.com/YACReader/yacreader-7z-deps/blob/main/7z2301-src.7z?raw=true" -O 7z2301-src.7z && \ - 7z x 7z2301-src.7z -o/src/7zip/lib7zip && \ +# ============================================================================ +# Stage 2: 7zip builder +# ============================================================================ +FROM plugin-base AS sevenzip-builder + +# Download 7z source +RUN mkdir -p /src/7zip +WORKDIR /src/7zip +RUN wget "https://github.com/YACReader/yacreader-7z-deps/blob/main/7z2301-src.7z?raw=true" -O 7z2301-src.7z + +# Extract 7z source +RUN 7z x 7z2301-src.7z -o/src/7zip/lib7zip && \ rm 7z2301-src.7z # Build 7z.so with RAR support -RUN cd "/src/7zip/lib7zip/CPP/7zip/Bundles/Format7zF" && \ - make -f makefile.gcc -j$(nproc) && \ - mkdir -p /app/lib/7zip && \ +WORKDIR /src/7zip/lib7zip/CPP/7zip/Bundles/Format7zF +RUN mkdir -p _o +RUN make -f makefile.gcc -j$(nproc) +RUN mkdir -p /app/lib/7zip && \ cp ./_o/7z.so /app/lib/7zip # ============================================================================ -# Stage 2: HEIC/HEIF plugin builder +# Stage 3: HEIC/HEIF plugin builder # ============================================================================ -FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS heic-plugin-builder - -ARG DEBIAN_FRONTEND="noninteractive" - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - cmake \ - git \ - qt6-base-dev \ - qt6-base-private-dev \ - libheif-dev \ - extra-cmake-modules \ - pkg-config && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* +FROM plugin-base AS heic-plugin-builder WORKDIR /tmp/qt-heic -RUN git clone https://github.com/novomesk/qt-heic-image-plugin.git . && \ - mkdir build && cd build && \ - cmake .. \ +RUN git clone https://github.com/novomesk/qt-heic-image-plugin.git . +RUN mkdir build +WORKDIR /tmp/qt-heic/build +RUN cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ - -DQT_MAJOR_VERSION=6 && \ - make -j$(nproc) && \ - make install DESTDIR=/output + -DQT_MAJOR_VERSION=6 +RUN make -j$(nproc) +RUN make install DESTDIR=/output # ============================================================================ -# Stage 3: libjxl builder (0.10.2 required for JxlEncoderDistanceFromQuality) +# Stage 4: libjxl + JXL plugin builder (merged) +# (0.10.2 required for JxlEncoderDistanceFromQuality) # ============================================================================ -FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS libjxl-builder - -ARG DEBIAN_FRONTEND="noninteractive" - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - cmake \ - git \ - pkg-config && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* +FROM plugin-base AS jxl-plugin-builder +# Build libjxl 0.10.2 WORKDIR /tmp/libjxl -RUN git clone --depth 1 --branch v0.10.2 https://github.com/libjxl/libjxl.git . && \ - ./deps.sh && \ - mkdir build && cd build && \ - cmake .. \ +RUN git clone --depth 1 --branch v0.10.2 https://github.com/libjxl/libjxl.git . +RUN ./deps.sh +RUN mkdir build +WORKDIR /tmp/libjxl/build +RUN cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_TESTING=OFF \ -DJPEGXL_ENABLE_BENCHMARK=OFF \ @@ -89,97 +88,57 @@ RUN git clone --depth 1 --branch v0.10.2 https://github.com/libjxl/libjxl.git . -DJPEGXL_ENABLE_MANPAGES=OFF \ -DJPEGXL_ENABLE_PLUGINS=OFF \ -DJPEGXL_ENABLE_TOOLS=OFF \ - -DCMAKE_INSTALL_PREFIX=/usr && \ - make -j$(nproc) && \ - make install DESTDIR=/output - -# ============================================================================ -# Stage 4: JXL plugin builder (depends on libjxl 0.10.2) -# ============================================================================ -FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS jxl-plugin-builder - -ARG DEBIAN_FRONTEND="noninteractive" - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - cmake \ - git \ - qt6-base-dev \ - qt6-base-private-dev \ - extra-cmake-modules \ - pkg-config && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -# Copy libjxl 0.10.2 from previous stage -COPY --from=libjxl-builder /output/usr /usr + -DCMAKE_INSTALL_PREFIX=/usr +RUN make -j$(nproc) +RUN make install +RUN make install DESTDIR=/output +# Build JXL plugin WORKDIR /tmp/qt-jxl -RUN git clone https://github.com/novomesk/qt-jpegxl-image-plugin.git . && \ - mkdir build && cd build && \ - cmake .. \ +RUN git clone https://github.com/novomesk/qt-jpegxl-image-plugin.git . +RUN mkdir build +WORKDIR /tmp/qt-jxl/build +RUN cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ - -DQT_MAJOR_VERSION=6 && \ - make -j$(nproc) && \ - make install DESTDIR=/output + -DQT_MAJOR_VERSION=6 +RUN make -j$(nproc) +RUN make install DESTDIR=/output # ============================================================================ # Stage 5: AVIF plugin builder # ============================================================================ -FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS avif-plugin-builder - -ARG DEBIAN_FRONTEND="noninteractive" - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - cmake \ - git \ - qt6-base-dev \ - qt6-base-private-dev \ - libavif-dev \ - extra-cmake-modules \ - pkg-config && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* +FROM plugin-base AS avif-plugin-builder WORKDIR /tmp/qt-avif -RUN git clone https://github.com/novomesk/qt-avif-image-plugin.git . && \ - mkdir build && cd build && \ - cmake .. \ +RUN git clone https://github.com/novomesk/qt-avif-image-plugin.git . +RUN mkdir build +WORKDIR /tmp/qt-avif/build +RUN cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ - -DQT_MAJOR_VERSION=6 && \ - make -j$(nproc) && \ - make install DESTDIR=/output + -DQT_MAJOR_VERSION=6 +RUN make -j$(nproc) +RUN make install DESTDIR=/output # ============================================================================ # Stage 6: YACReader builder # ============================================================================ -FROM ghcr.io/linuxserver/baseimage-ubuntu:noble AS yacreader-builder +FROM plugin-base AS yacreader-builder ARG YACR_VERSION="develop" -ARG DEBIAN_FRONTEND="noninteractive" ENV APPNAME="YACReaderLibraryServer" ENV HOME="/config" LABEL maintainer="luisangelsm" -# Install build packages +# Install YACReader-specific build packages (common packages inherited from plugin-base) RUN apt-get update && \ apt-get install -y --no-install-recommends \ - build-essential \ desktop-file-utils \ - gcc \ - g++ \ - git \ - cmake \ qt6-tools-dev \ qt6-base-dev-tools \ qmake6 \ qmake6-bin \ - qt6-base-dev \ qt6-multimedia-dev \ qt6-tools-dev-tools \ libgl-dev \ @@ -200,13 +159,8 @@ RUN apt-get update && \ qt6-image-formats-plugins \ libqt6sql6 \ libqt6sql6-sqlite \ - make \ sqlite3 \ libsqlite3-dev \ - unzip \ - wget \ - libavif-dev \ - 7zip \ 7zip-rar \ libpoppler-qt6-dev \ zlib1g-dev && \ @@ -241,7 +195,7 @@ RUN cd /src/git/YACReaderLibraryServer && \ # ============================================================================ # Stage 7: Final runtime image (minimal, no build assets) # ============================================================================ -FROM ghcr.io/linuxserver/baseimage-ubuntu:noble +FROM base AS runtime ENV APPNAME="YACReaderLibraryServer" ENV HOME="/config" @@ -274,7 +228,7 @@ COPY --from=heic-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/ima /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ # Copy libjxl 0.10.2 runtime libraries (not available in Ubuntu noble) -COPY --from=libjxl-builder /output/usr/lib/ /usr/lib/ +COPY --from=jxl-plugin-builder /output/usr/lib/ /usr/lib/ # Refresh dynamic linker cache RUN ldconfig From d3c78310ed61dfecb313bd7fbf2bc7f21f64baf7 Mon Sep 17 00:00:00 2001 From: Nick Vance Date: Sun, 25 Jan 2026 21:13:15 -0800 Subject: [PATCH 3/5] feat(docker): Replace custom plugin builds with KDE kimageformats - Replace 3 separate image plugin builders (AVIF, JXL, HEIC) with single kimageformats build - Reduce Dockerfile from 8 stages to 6 stages (25% reduction) - Build kimageformats 6.0.0 from KDE frameworks (patched for Qt 6.4 compatibility) - Support AVIF (avif, avifs) and JPEG XL (jxl) formats - Add 30+ bonus image formats (PSD, QOI, XCF, HDR, etc.) - Simplify build dependencies and maintenance - Note: HEIC/HEIF support not included (kimageformats 6.0.0 limitation) This provides a minimal diff alternative to PR #499 as requested by maintainers, using well-maintained KDE framework instead of multiple custom plugin builds. --- docker/Dockerfile | 139 +++++++++++++++++----------------------------- 1 file changed, 50 insertions(+), 89 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index a8b1379c3..cf40b6ce2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,8 +20,6 @@ RUN apt-get update && \ g++ \ gcc \ git \ - libavif-dev \ - libheif-dev \ make \ qt6-base-dev \ qt6-base-private-dev \ @@ -32,97 +30,70 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* # ============================================================================ -# Stage 2: 7zip builder +# Stage 2: kimageformats builder # ============================================================================ -FROM plugin-base AS sevenzip-builder - -# Download 7z source -RUN mkdir -p /src/7zip -WORKDIR /src/7zip -RUN wget "https://github.com/YACReader/yacreader-7z-deps/blob/main/7z2301-src.7z?raw=true" -O 7z2301-src.7z - -# Extract 7z source -RUN 7z x 7z2301-src.7z -o/src/7zip/lib7zip && \ - rm 7z2301-src.7z - -# Build 7z.so with RAR support -WORKDIR /src/7zip/lib7zip/CPP/7zip/Bundles/Format7zF -RUN mkdir -p _o -RUN make -f makefile.gcc -j$(nproc) -RUN mkdir -p /app/lib/7zip && \ - cp ./_o/7z.so /app/lib/7zip +FROM plugin-base AS kimageformats-builder -# ============================================================================ -# Stage 3: HEIC/HEIF plugin builder -# ============================================================================ -FROM plugin-base AS heic-plugin-builder +# Install additional dependencies for kimageformats +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libavif-dev \ + libheif-dev \ + libjxl-dev \ + libarchive-dev && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* -WORKDIR /tmp/qt-heic -RUN git clone https://github.com/novomesk/qt-heic-image-plugin.git . +# Build ECM 6.0.0 for KF6 (compatible with Qt 6.4) +WORKDIR /tmp/ecm +RUN git clone --depth 1 --branch v6.0.0 https://invent.kde.org/frameworks/extra-cmake-modules.git . RUN mkdir build -WORKDIR /tmp/qt-heic/build +WORKDIR /tmp/ecm/build RUN cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ - -DQT_MAJOR_VERSION=6 -RUN make -j$(nproc) -RUN make install DESTDIR=/output - -# ============================================================================ -# Stage 4: libjxl + JXL plugin builder (merged) -# (0.10.2 required for JxlEncoderDistanceFromQuality) -# ============================================================================ -FROM plugin-base AS jxl-plugin-builder - -# Build libjxl 0.10.2 -WORKDIR /tmp/libjxl -RUN git clone --depth 1 --branch v0.10.2 https://github.com/libjxl/libjxl.git . -RUN ./deps.sh -RUN mkdir build -WORKDIR /tmp/libjxl/build -RUN cmake .. \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_TESTING=OFF \ - -DJPEGXL_ENABLE_BENCHMARK=OFF \ - -DJPEGXL_ENABLE_EXAMPLES=OFF \ - -DJPEGXL_ENABLE_MANPAGES=OFF \ - -DJPEGXL_ENABLE_PLUGINS=OFF \ - -DJPEGXL_ENABLE_TOOLS=OFF \ - -DCMAKE_INSTALL_PREFIX=/usr + -DBUILD_TESTING=OFF RUN make -j$(nproc) RUN make install -RUN make install DESTDIR=/output -# Build JXL plugin -WORKDIR /tmp/qt-jxl -RUN git clone https://github.com/novomesk/qt-jpegxl-image-plugin.git . +# Build kimageformats 6.0.0 from KDE source (patched for Qt 6.4) +WORKDIR /tmp/kimageformats +RUN git clone --depth 1 --branch v6.0.0 https://invent.kde.org/frameworks/kimageformats.git . +# Patch to work with Qt 6.4 (Noble has 6.4.2, kimageformats wants 6.5+) +RUN sed -i 's/6\.5\.0/6.4.0/g' CMakeLists.txt RUN mkdir build -WORKDIR /tmp/qt-jxl/build +WORKDIR /tmp/kimageformats/build RUN cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ + -DBUILD_TESTING=OFF \ -DQT_MAJOR_VERSION=6 RUN make -j$(nproc) RUN make install DESTDIR=/output # ============================================================================ -# Stage 5: AVIF plugin builder +# Stage 3: 7zip builder # ============================================================================ -FROM plugin-base AS avif-plugin-builder +FROM plugin-base AS sevenzip-builder -WORKDIR /tmp/qt-avif -RUN git clone https://github.com/novomesk/qt-avif-image-plugin.git . -RUN mkdir build -WORKDIR /tmp/qt-avif/build -RUN cmake .. \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DQT_MAJOR_VERSION=6 -RUN make -j$(nproc) -RUN make install DESTDIR=/output +# Download 7z source +RUN mkdir -p /src/7zip +WORKDIR /src/7zip +RUN wget "https://github.com/YACReader/yacreader-7z-deps/blob/main/7z2301-src.7z?raw=true" -O 7z2301-src.7z + +# Extract 7z source +RUN 7z x 7z2301-src.7z -o/src/7zip/lib7zip && \ + rm 7z2301-src.7z + +# Build 7z.so with RAR support +WORKDIR /src/7zip/lib7zip/CPP/7zip/Bundles/Format7zF +RUN mkdir -p _o +RUN make -f makefile.gcc -j$(nproc) +RUN mkdir -p /app/lib/7zip && \ + cp ./_o/7z.so /app/lib/7zip # ============================================================================ -# Stage 6: YACReader builder +# Stage 4: YACReader builder # ============================================================================ FROM plugin-base AS yacreader-builder @@ -177,12 +148,8 @@ RUN git clone https://github.com/YACReader/yacreader.git /src/git && \ COPY --from=sevenzip-builder /src/7zip/lib7zip /src/git/compressed_archive/lib7zip COPY --from=sevenzip-builder /app/lib/7zip /app/lib/7zip -# Copy Qt image format plugins from separate stages -COPY --from=avif-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ - /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ -COPY --from=jxl-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ - /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ -COPY --from=heic-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ +# Copy kimageformats Qt6 plugins +COPY --from=kimageformats-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ # Build YACReaderLibraryServer @@ -193,7 +160,7 @@ RUN cd /src/git/YACReaderLibraryServer && \ make install # ============================================================================ -# Stage 7: Final runtime image (minimal, no build assets) +# Stage 5: Final runtime image (minimal, no build assets) # ============================================================================ FROM base AS runtime @@ -209,26 +176,20 @@ RUN apt-get update && \ libqt6core5compat6 \ libpoppler-qt6-3t64 \ qt6-image-formats-plugins \ - libqt6network6t64 \ - libqt6sql6-sqlite \ libavif16 \ - libheif1 && \ + libheif1 \ + libjxl0.7 \ + libqt6network6t64 \ + libqt6sql6-sqlite && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # Copy YACReaderLibraryServer application from builder COPY --from=yacreader-builder /app /app -# Copy Qt image format plugins from plugin builders -COPY --from=avif-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ - /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ -COPY --from=jxl-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ +# Copy kimageformats Qt6 plugins (must be done before ldconfig) +COPY --from=kimageformats-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/*.so \ /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ -COPY --from=heic-plugin-builder /output/usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ \ - /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ - -# Copy libjxl 0.10.2 runtime libraries (not available in Ubuntu noble) -COPY --from=jxl-plugin-builder /output/usr/lib/ /usr/lib/ # Refresh dynamic linker cache RUN ldconfig From c3c12b9798d73486217399b29fe0d07f1e2f0ab8 Mon Sep 17 00:00:00 2001 From: Nick Vance Date: Sun, 25 Jan 2026 21:18:13 -0800 Subject: [PATCH 4/5] refactor: Remove unnecessary HEIF dependencies - Remove libheif-dev from kimageformats builder (HEIC/HEIF not supported in v6.0.0) - Remove libheif1 from runtime dependencies - Reduces build complexity and image size - No functional change since HEIC/HEIF wasn't working anyway --- docker/Dockerfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index cf40b6ce2..19050ff8f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -38,7 +38,6 @@ FROM plugin-base AS kimageformats-builder RUN apt-get update && \ apt-get install -y --no-install-recommends \ libavif-dev \ - libheif-dev \ libjxl-dev \ libarchive-dev && \ apt-get clean && \ @@ -177,7 +176,6 @@ RUN apt-get update && \ libpoppler-qt6-3t64 \ qt6-image-formats-plugins \ libavif16 \ - libheif1 \ libjxl0.7 \ libqt6network6t64 \ libqt6sql6-sqlite && \ From eb76672be0ac53f828028aa403e09ca2779e0296 Mon Sep 17 00:00:00 2001 From: Nick Vance Date: Sun, 25 Jan 2026 21:30:08 -0800 Subject: [PATCH 5/5] docs: Add testing guide for kimageformats Docker implementation - Step-by-step testing instructions - Expected outputs and success criteria - Known limitations (HEIC/HEIF not supported) - Troubleshooting section - Comparison with original PR #499 approach --- docker/TESTING.md | 153 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 docker/TESTING.md diff --git a/docker/TESTING.md b/docker/TESTING.md new file mode 100644 index 000000000..388fd82ae --- /dev/null +++ b/docker/TESTING.md @@ -0,0 +1,153 @@ +# Docker Image Format Testing Guide + +## Overview +This document describes how to test the kimageformats-based Docker image for YACReaderLibraryServer with AVIF and JXL support. + +## Prerequisites +- Docker installed +- Test comics with various image formats available at `/exos/comics/Mylar/_Incoming_Downloads/Format testing/` +- Files needed: `avif.cbz`, `jxl.cbz`, `test_combined.cbz` + +## Build the Image + +```bash +cd /home/nick/yacreader +docker build -f docker/Dockerfile -t yacreader-test:kimageformats . +``` + +Expected: Build completes successfully with 6 stages (base, plugin-base, kimageformats-builder, sevenzip-builder, yacreader-builder, runtime) + +## Copy Test Files + +```bash +mkdir -p /home/nick/yacreader/test-comics +cp "/exos/comics/Mylar/_Incoming_Downloads/Format testing/"*.cbz /home/nick/yacreader/test-comics/ +ls -la /home/nick/yacreader/test-comics/ +``` + +Expected: See avif.cbz, jxl.cbz, test_combined.cbz, test_heic.cbz, test_heif.cbz + +## Run Container + +```bash +docker rm -f YACReaderTest 2>/dev/null +docker run --rm -d \ + --name YACReaderTest \ + -p 8086:8080 \ + -v /home/nick/yacreader/test-comics:/comics \ + -e PUID=$(id -u) \ + -e PGID=$(id -g) \ + yacreader-test:kimageformats + +# Wait for startup +sleep 5 +``` + +## Verify Image Format Support + +```bash +docker logs YACReaderTest 2>&1 | grep "Image formats" +``` + +Expected output should include: +- `avif` ✅ +- `avifs` ✅ +- `jxl` ✅ +- Plus bonus formats: ani, hdr, pcx, psd, qoi, xcf, etc. + +**Should NOT include:** heic, heif (not supported in kimageformats 6.0.0) + +## Create and Scan Library + +```bash +# Create .yacreaderlibrary directory with correct permissions +docker exec -u abc YACReaderTest mkdir -p /comics/.yacreaderlibrary + +# Create library and scan comics +docker exec YACReaderTest YACReaderLibraryServer create-library "TestComics" /comics +``` + +Expected output: +``` +Processing comics...Done! +Number of comics processed = 3 +``` + +Note: Only 3 comics should be processed (avif.cbz, jxl.cbz, test_combined.cbz). The HEIC/HEIF files are skipped because format not supported. + +## Verify Comics via Web Interface + +```bash +curl -s http://localhost:8086/library/1/folder/1 | grep -i "comic" | head -15 +``` + +Expected: HTML output showing 3 comics with sizes and page counts + +## Check Specific Comic Details + +```bash +docker exec YACReaderTest ls -la /comics/.yacreaderlibrary/ +``` + +Expected: +- `library.ydb` (SQLite database) +- `covers/` directory +- `id` file + +## Verify Plugins Are Installed + +```bash +docker exec YACReaderTest ls -la /usr/lib/x86_64-linux-gnu/qt6/plugins/imageformats/ | grep kimg +``` + +Expected output should include: +- `kimg_avif.so` ✅ +- `kimg_jxl.so` ✅ +- Plus: kimg_ani.so, kimg_hdr.so, kimg_pcx.so, kimg_psd.so, kimg_qoi.so, kimg_xcf.so, etc. + +## Cleanup + +```bash +docker stop YACReaderTest +docker rm YACReaderTest 2>/dev/null +``` + +## Known Limitations + +1. **HEIC/HEIF not supported**: kimageformats 6.0.0 (compatible with Ubuntu Noble's Qt 6.4.2) doesn't include HEIC/HEIF plugins. Test files `test_heic.cbz` and `test_heif.cbz` will be skipped during library scan. + +2. **Compatibility patch required**: kimageformats 6.0.0 requires Qt 6.5+, but Ubuntu Noble has Qt 6.4.2. The Dockerfile includes a sed command to patch the version check: `sed -i 's/6\.5\.0/6.4.0/g' CMakeLists.txt` + +## Success Criteria + +- [x] Build completes without errors +- [x] Container starts and shows AVIF/JXL in supported formats +- [x] Library creation processes 3 comics successfully +- [x] Web interface shows all 3 comics +- [x] kimageformats plugins are installed in correct location +- [x] HEIC/HEIF files are gracefully skipped (not errors) + +## Comparison Test (Optional) + +Compare with the original PR #499 implementation: + +```bash +# Original (PR #499) +docker logs YACReaderLibraryServer 2>&1 | grep "Image formats" +# Should show: avif, avifs, heic, heif, jxl + +# New (kimageformats) +docker logs YACReaderTest 2>&1 | grep "Image formats" +# Should show: avif, avifs, jxl (+ 30+ bonus formats, no heic/heif) +``` + +## Troubleshooting + +**Problem:** "Unable to find database at: /comics/.yacreaderlibrary" +- **Solution:** Ensure .yacreaderlibrary directory exists with correct permissions. Use `create-library` instead of `add-library` + `update-library`. + +**Problem:** No comics scanned +- **Solution:** Check file permissions. Container runs as uid/gid 1000 (abc user). Files should be readable by this user. + +**Problem:** kimageformats plugins not found +- **Solution:** Verify COPY command in Dockerfile uses `*.so` wildcard and paths match build output structure.