Add fallback if ImageMagick is not available

This commit is contained in:
Kylian Schmidt
2026-05-15 09:07:48 +02:00
parent 73916268a2
commit 3c399d5733
4 changed files with 265 additions and 249 deletions
+36 -8
View File
@@ -5,6 +5,14 @@ import subprocess
from pathlib import Path
from typing import Any, Dict
try:
import fitz # PyMuPDF
_PYMUPDF_AVAILABLE = True
except ImportError:
_PYMUPDF_AVAILABLE = False
_IMAGEMAGICK_AVAILABLE = shutil.which("convert") is not None
from jinja2 import Template
from gallery.utils.metadata import (
@@ -184,17 +192,15 @@ def render_gallery_page(
def convert_pdf_to_png(pdf_path: Path, config: GalleryConfig) -> None:
"""
Convert a PDF file to PNG format using ImageMagick.
Convert a PDF file to PNG format.
Uses PyMuPDF (fitz) when available; falls back to ImageMagick otherwise.
Only converts if the PNG doesn't exist or if the PDF is newer than
the PNG (with a 30-second buffer to handle filesystem timing issues).
Args:
pdf_path: Path to the source PDF file
config: Gallery configuration object
Raises:
subprocess.CalledProcessError: If ImageMagick conversion fails
RuntimeError: If neither PyMuPDF nor ImageMagick is available.
subprocess.CalledProcessError: If the ImageMagick fallback fails.
"""
png_path = pdf_path.with_suffix(".png")
@@ -204,12 +210,34 @@ def convert_pdf_to_png(pdf_path: Path, config: GalleryConfig) -> None:
if png_mtime >= (pdf_mtime + 30):
return
if _PYMUPDF_AVAILABLE:
_convert_pdf_pymupdf(pdf_path, png_path, config.png_dpi)
elif _IMAGEMAGICK_AVAILABLE:
_convert_pdf_imagemagick(pdf_path, png_path, config.png_dpi)
else:
raise RuntimeError(
"No PDF renderer found. Install PyMuPDF (`pip install pymupdf`) "
"or ImageMagick (`apt-get install imagemagick`)."
)
def _convert_pdf_pymupdf(pdf_path: Path, png_path: Path, dpi: int) -> None:
zoom = dpi / 72 # PDF coordinate space is 72 pt/inch
doc = fitz.open(str(pdf_path))
try:
pix = doc[0].get_pixmap(matrix=fitz.Matrix(zoom, zoom))
pix.save(str(png_path))
finally:
doc.close()
def _convert_pdf_imagemagick(pdf_path: Path, png_path: Path, dpi: int) -> None:
subprocess.run([
"convert",
"-density", str(config.png_dpi),
"-density", str(dpi),
str(pdf_path),
"-quality", "95",
str(png_path)
str(png_path),
], check=True)