From a3c87fcde460e9ed5deabcad6f6483c3bd7e1c45 Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Sun, 9 Aug 2026 11:34:07 +0200 Subject: [PATCH] fix: normalize raster images before img2pdf retry img2pdf refuses images with alpha channels or more than 8 bits per channel (common for screenshots). Normalize such images to opaque 8-bit with ImageMagick and retry img2pdf before falling back to a full ImageMagick PDF conversion. --- src/main.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 3513145..96cec21 100644 --- a/src/main.rs +++ b/src/main.rs @@ -842,7 +842,8 @@ fn path_hash(path: &Path) -> u64 { /// Print the currently active document to the system printer via CUPS (lp). /// /// - **PDF** → sent directly to CUPS via `lp` -/// - **Raster images** → converted to PDF via `img2pdf` (or `convert` as fallback) +/// - **Raster images** → converted to PDF via `img2pdf` (normalized to +/// opaque 8-bit when needed, or `convert` as fallback) /// - **SVG** → converted to PDF via `pdftocairo` → `img2pdf` fn print_document_sync(path: &Path, kind: DocumentKind) -> Result<(), String> { let pdf_path = match kind { @@ -861,10 +862,45 @@ fn convert_raster_to_pdf(path: &Path) -> Result { return Ok(result); } + // img2pdf refuses alpha channels and >8 bit channels: normalize to + // opaque 8-bit and retry before falling back to ImageMagick. + if let Ok(normalized) = normalize_raster(path) { + let result = convert_with_cmd( + "img2pdf", + vec![normalized.to_string_lossy().into_owned()], + path, + ); + let _ = std::fs::remove_file(&normalized); + if let Ok(result) = result { + return Ok(result); + } + } + // Fallback: ImageMagick convert convert_with_cmd("convert", vec![path.to_string_lossy().into_owned()], path) } +fn normalize_raster(path: &Path) -> Result { + let extension = path.extension().and_then(OsStr::to_str).unwrap_or("png"); + let output_path = temp_prefix(path, "normalized").with_extension(extension); + + let status = Command::new("convert") + .arg(path) + .args(["-depth", "8", "-alpha", "off"]) + .arg(&output_path) + .status() + .map_err(|e| format!("Failed to run convert: {e}"))?; + if !status.success() { + return Err("convert failed".to_string()); + } + + if output_path.exists() { + Ok(output_path) + } else { + Err("convert did not produce output".to_string()) + } +} + fn convert_svg_to_pdf(path: &Path) -> Result { // Render SVG to PNG with pdftocairo, then convert PNG to PDF let prefix = temp_prefix(path, "svg");