From 80b452ad6c7ff1f4efb60d48bc31a9ffce5ed42c Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 11 Nov 2026 03:54:56 -0800 Subject: [PATCH] Rasterize: art that is exactly 32,768 pixels a side at the resolution is accepted The side limit compared the region's height in points times the scale with 32,768. Far from the origin the snapped region can come back a fraction of a pixel over, so art that the renderer draws at exactly 32,768 pixels was refused (a rectangle at y = 100,000 rasterized at 400 ppi). The check now uses the renderer's own rounded pixel width and height. --- crates/engine/src/cmd/menucmds.rs | 8 +++++--- crates/engine/src/tests/menucmds.rs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/crates/engine/src/cmd/menucmds.rs b/crates/engine/src/cmd/menucmds.rs index ba6941eb0..8ea016db6 100644 --- a/crates/engine/src/cmd/menucmds.rs +++ b/crates/engine/src/cmd/menucmds.rs @@ -670,9 +670,11 @@ fn render_pixels( opts: &vectorcraft_render::RenderOptions, color: RasterColorModel, ) -> Result<(vectorcraft_render::Rendered, Option<&'static str>)> { - // No side longer than the renderer draws: it would cut the image off there. - let side = f64::from(vectorcraft_render::MAX_RASTER_SIDE); - if region.width() * region.height() * scale * scale > MAX_PIXELS || region.width() * scale > side || region.height() * scale > side { + // No side longer than the renderer draws: it would cut the image off there. The sides are + // measured in the renderer's whole pixels. + let side = vectorcraft_render::MAX_RASTER_SIDE; + let (w, h) = vectorcraft_render::region_pixels(region, scale); + if region.width() * region.height() * scale * scale > MAX_PIXELS || w > side || h > side { return Err(EngineError::Other("image would be too large; lower the resolution".into())); } let mut r = vectorcraft_render::Renderer::new(); diff --git a/crates/engine/src/tests/menucmds.rs b/crates/engine/src/tests/menucmds.rs index 7ebe24716..e1def8a6f 100644 --- a/crates/engine/src/tests/menucmds.rs +++ b/crates/engine/src/tests/menucmds.rs @@ -1481,6 +1481,22 @@ fn rasterize_refuses_an_image_longer_than_the_renderer_draws() { assert!(close(b.y0, vb.y0) && b.y1 >= vb.y1, "{b:?} covers {vb:?}"); } +/// Art that snaps to exactly 32,768 pixels a side is rasterized, wherever it is on the canvas. +#[test] +fn rasterize_takes_art_that_snaps_to_32768_pixels_a_side() { + let scale = 400.0 / 72.0; + for y in [100_000.0, 250_000.0, 333_333.3, 777_777.7] { + let mut s = session(); + let probe = rect(&mut s, 10.0, y, 100.0, 5898.0); + let vb = s.doc().unwrap().doc.bounds_of(&[probe], true).unwrap(); + let h = 5898.0 + (32_767.8 / scale - vb.height()); + let a = rect(&mut s, 200.0, y, 100.0, h); + sel(&mut s, &[a]); + let r = s.execute("object.rasterize", &json!({"ppi": 400, "padding": 0})).unwrap_or_else(|e| panic!("at y = {y}: {e}")); + assert_eq!(r["height"].as_u64(), Some(u64::from(vectorcraft_render::MAX_RASTER_SIDE)), "at y = {y}: {r}"); + } +} + /// Rasterize refuses a resolution given as text or as another value that is not a number, and the /// selected art stays as it was. #[test]