From 39a8234633ef139c635b847baf5f4a57cd997664 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 12 Oct 2026 17:45:31 -0400 Subject: [PATCH] Render: slide backgrounds are laid over white (#275) PowerPoint shows white around a background picture stretched into part of the slide and under a see-through background colour. DeckCraft left those areas transparent, which exports and the slide show draw black. Co-authored-by: Claude Opus 5.5 (1M context) --- crates/render/src/lib.rs | 4 ++++ crates/render/src/tests.rs | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/crates/render/src/lib.rs b/crates/render/src/lib.rs index e26f8c6..29f60c0 100644 --- a/crates/render/src/lib.rs +++ b/crates/render/src/lib.rs @@ -592,6 +592,10 @@ impl Renderer { let r = Rect::new(0.0, 0.0, f.pres.slide_size.width, f.pres.slide_size.height); ctx.set_transform(view); let path = r.to_path(0.1); + // PowerPoint lays every background over white: a picture stretched into part of the + // slide, or a see-through colour, leaves white around and under it. + ctx.set_paint(color(Rgba::WHITE, 1.0)); + ctx.fill_path(&path); paint::fill_path(ctx, rctx, &fill, ph, &path, r, view, FillMode::Norm, 1.0, f.pres); self.bg = Some((fill, ph, view)); } diff --git a/crates/render/src/tests.rs b/crates/render/src/tests.rs index 7f0ef96..936dce3 100644 --- a/crates/render/src/tests.rs +++ b/crates/render/src/tests.rs @@ -610,3 +610,25 @@ fn a_shape_filled_with_the_background_shows_the_slide_background() { let v = img.pixel(720, 270)[0] as i32; assert!((v - 100).abs() <= 6, "{v}"); } + +#[test] +fn a_background_is_laid_over_white() { + // A background picture stretched into the bottom-right quarter (fillRect l=50% t=50%), and a + // half-transparent colour: PowerPoint shows white around and under them, not transparency. + use deckcraft_model::style::{Fill, PictureFill, PictureMode}; + let mut png = std::io::Cursor::new(Vec::new()); + image::DynamicImage::ImageRgb8(image::RgbImage::from_pixel(4, 4, image::Rgb([0, 0, 200]))).write_to(&mut png, image::ImageFormat::Png).unwrap(); + let mut p = deck_with(vec![]); + let media = p.add_media("bg.png", "image/png", png.into_inner()); + let pf = PictureFill { media, mode: PictureMode::Stretch { fill_rect: [0.5, 0.5, 0.0, 0.0] }, ..Default::default() }; + std::sync::Arc::make_mut(&mut p.slides[0]).background = Some(deckcraft_model::Background::Fill { fill: Fill::Picture(pf) }); + let img = render_slide(&p, 0, &RenderOpts { scale: 0.5, ..Default::default() }); + assert_eq!(img.pixel(20, 20), [255, 255, 255, 255], "white where the picture doesn't reach"); + let q = img.pixel(400, 230); + assert!(q[2] > 190 && q[0] < 10 && q[3] == 255, "{q:?}"); + let see_through = ColorRef::rgb(deckcraft_color::Rgba { r: 0, g: 0, b: 0, a: 128 }); + std::sync::Arc::make_mut(&mut p.slides[0]).background = Some(deckcraft_model::Background::Fill { fill: Fill::solid(see_through) }); + let img = render_slide(&p, 0, &RenderOpts { scale: 0.5, ..Default::default() }); + let g = img.pixel(20, 20); + assert!(g[3] == 255 && (g[0] as i32 - 127).abs() <= 3, "half-transparent black over white is grey: {g:?}"); +}