Render: a picture's shadow covers the whole picture
The shadow of a picture is the picture recoloured to the shadow colour, but drawing the picture left its pixel-space transform set, so the recolouring rectangle (sized in points) covered only part of a picture whose bitmap is bigger than it is shown: a 400 px photo at 240 pt cast a shadow of its top-left corner only. The shape's transform is restored before recolouring. Wild synthetic set: framed pictures with shadows 7.67 -> 5.95, rotated picture with a shadow 10.67 -> 10.07. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
22070a3610
commit
fa1db7809a
|
|
@ -1224,6 +1224,9 @@ impl Renderer {
|
|||
Some(pf) => {
|
||||
ctx.push_clip_layer(&silhouette);
|
||||
paint::picture(ctx, rctx.pres, pf, Rect::new(0.0, 0.0, w, h), sm, None);
|
||||
// Drawing the picture leaves its own pixel transform set: back to the shape's,
|
||||
// or the recolouring below covers only part of a large picture's shadow.
|
||||
ctx.set_transform(sm);
|
||||
ctx.push_layer(None, Some(peniko::BlendMode::new(peniko::Mix::Normal, peniko::Compose::SrcIn)), None, None, None);
|
||||
ctx.set_paint(color(c.with_alpha(255), 1.0));
|
||||
ctx.fill_rect(&Rect::new(0.0, 0.0, w, h).inflate(1.0, 1.0));
|
||||
|
|
|
|||
|
|
@ -598,3 +598,37 @@ fn table_borders_take_their_dashes_and_diagonals_are_drawn() {
|
|||
// The diagonal from top-left to bottom-right passes through the middle.
|
||||
assert!(close(img.pixel(200, 150), Rgba::rgb(0, 0, 255), 40), "{:?}", img.pixel(200, 150));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_large_pictures_shadow_is_whole() {
|
||||
// A 400 px picture shown at 240 pt: its shadow was recoloured in the picture's pixel space and
|
||||
// covered only part of it.
|
||||
let mut counts = vec![];
|
||||
for side in [8u32, 400] {
|
||||
let mut p = Presentation::default();
|
||||
let media = p.add_media("image1.png", "image/png", png(side, side * 3 / 4, [0, 0, 255]));
|
||||
let mut fx = offset_shadow();
|
||||
if let Some(o) = &mut fx.outer_shadow {
|
||||
o.blur = 8.0;
|
||||
}
|
||||
let sh = Shape {
|
||||
id: ShapeId(15),
|
||||
xfrm: Some(Xfrm { rot: 20.0, ..Xfrm::new(360.0, 300.0, 240.0, 160.0) }),
|
||||
kind: ShapeKind::Picture { fill: deckcraft_model::style::PictureFill { media, ..Default::default() } },
|
||||
effects: Some(fx),
|
||||
..Default::default()
|
||||
};
|
||||
std::sync::Arc::make_mut(&mut p.slides[0]).shapes = vec![sh];
|
||||
let img = render_slide(&p, 0, &RenderOpts { scale: 1.0, ..Default::default() });
|
||||
counts.push(
|
||||
(0..img.height)
|
||||
.flat_map(|y| (0..img.width).map(move |x| (x, y)))
|
||||
.filter(|(x, y)| {
|
||||
let q = img.pixel(*x, *y);
|
||||
q[0] < 200 && q[2] < 200
|
||||
})
|
||||
.count(),
|
||||
);
|
||||
}
|
||||
assert!(counts[1] > 3000 && (counts[0] as i64 - counts[1] as i64).abs() < 300, "{counts:?}");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue